diff --git a/Yggdrasil Backup.xcframework/Info.plist b/Yggdrasil Backup.xcframework/Info.plist new file mode 100644 index 0000000..7e611e0 --- /dev/null +++ b/Yggdrasil Backup.xcframework/Info.plist @@ -0,0 +1,38 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + Yggdrasil.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + LibraryIdentifier + ios-arm64 + LibraryPath + Yggdrasil.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Yggdrasil Network Cross-Platform/ConfigurationProxy.swift b/Yggdrasil Network Cross-Platform/ConfigurationProxy.swift index e75696b..0180afc 100644 --- a/Yggdrasil Network Cross-Platform/ConfigurationProxy.swift +++ b/Yggdrasil Network Cross-Platform/ConfigurationProxy.swift @@ -10,6 +10,7 @@ import UIKit #elseif canImport(AppKit) import AppKit #endif +import SwiftUI import Yggdrasil import NetworkExtension @@ -28,12 +29,14 @@ class PlatformItemSource: NSObject {} #endif class ConfigurationProxy: PlatformItemSource { - + private var manager: NETunnelProviderManager? private var json: Data? = nil private var dict: [String: Any]? = nil - override init() { + init(manager: NETunnelProviderManager? = nil) { + self.manager = manager super.init() + self.json = MobileGenerateConfigJSON() do { try self.convertToDict() @@ -48,8 +51,10 @@ class ConfigurationProxy: PlatformItemSource { self.fix() } - init(json: Data) throws { + init(json: Data, manager: NETunnelProviderManager? = nil) throws { + self.manager = manager super.init() + self.json = json try self.convertToDict() self.fix() @@ -59,9 +64,10 @@ class ConfigurationProxy: PlatformItemSource { self.set("Listen", to: [] as [String]) self.set("AdminListen", to: "none") self.set("IfName", to: "dummy") + // self.set("Peers", to: ["tcp://172.22.97.1.5190", "tls://172.22.97.1:5191"]) if self.get("AutoStart") == nil { - self.set("AutoStart", to: ["WiFi": false, "Mobile": false] as [String: Bool]) + self.set("AutoStart", to: ["Any": false, "WiFi": false, "Mobile": false, "Ethernet": false] as [String: Bool]) } let multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? [] @@ -88,6 +94,7 @@ class ConfigurationProxy: PlatformItemSource { var multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? [] multicastInterfaces[0]["Beacon"] = newValue self.set("MulticastInterfaces", to: multicastInterfaces) + self.trySave() } } @@ -103,10 +110,61 @@ class ConfigurationProxy: PlatformItemSource { var multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? [] multicastInterfaces[0]["Listen"] = newValue self.set("MulticastInterfaces", to: multicastInterfaces) + self.trySave() + } + } + + public var autoStartAny: Bool { + get { + return self.get("Any", inSection: "AutoStart") as? Bool ?? false + } + set { + self.set("Any", inSection: "AutoStart", to: newValue) + self.trySave() + } + } + + public var autoStartWiFi: Bool { + get { + return self.get("WiFi", inSection: "AutoStart") as? Bool ?? false + } + set { + self.set("WiFi", inSection: "AutoStart", to: newValue) + self.trySave() } } - func get(_ key: String) -> Any? { + public var autoStartEthernet: Bool { + get { + return self.get("Ethernet", inSection: "AutoStart") as? Bool ?? false + } + set { + self.set("Ethernet", inSection: "AutoStart", to: newValue) + self.trySave() + } + } + + public var autoStartMobile: Bool { + get { + return self.get("Mobile", inSection: "AutoStart") as? Bool ?? false + } + set { + self.set("Mobile", inSection: "AutoStart", to: newValue) + self.trySave() + } + } + + public var peers: [String] { + get { + return self.get("Peers") as? [String] ?? [] + } + set { + self.set("Peers", to: newValue) + self.trySave() + } + } + + private func get(_ key: String) -> Any? { if let dict = self.dict { if dict.keys.contains(key) { return dict[key] @@ -115,7 +173,7 @@ class ConfigurationProxy: PlatformItemSource { return nil } - func get(_ key: String, inSection section: String) -> Any? { + private func get(_ key: String, inSection section: String) -> Any? { if let dict = self.get(section) as? [String: Any] { if dict.keys.contains(key) { return dict[key] @@ -124,7 +182,7 @@ class ConfigurationProxy: PlatformItemSource { return nil } - func add(_ value: Any, in key: String) { + private func add(_ value: Any, in key: String) { if self.dict != nil { if self.dict![key] as? [Any] != nil { var temp = self.dict![key] as? [Any] ?? [] @@ -134,7 +192,7 @@ class ConfigurationProxy: PlatformItemSource { } } - func remove(_ value: String, from key: String) { + private func remove(_ value: String, from key: String) { if self.dict != nil { if self.dict![key] as? [String] != nil { var temp = self.dict![key] as? [String] ?? [] @@ -146,7 +204,7 @@ class ConfigurationProxy: PlatformItemSource { } } - func remove(index: Int, from key: String) { + private func remove(index: Int, from key: String) { if self.dict != nil { if self.dict![key] as? [Any] != nil { var temp = self.dict![key] as? [Any] ?? [] @@ -156,13 +214,13 @@ class ConfigurationProxy: PlatformItemSource { } } - func set(_ key: String, to value: Any) { + private func set(_ key: String, to value: Any) { if self.dict != nil { self.dict![key] = value } } - func set(_ key: String, inSection section: String, to value: Any?) { + private func set(_ key: String, inSection section: String, to value: Any?) { if self.dict != nil { if self.dict!.keys.contains(section), let value = value { var temp = self.dict![section] as? [String: Any] ?? [:] @@ -181,6 +239,12 @@ class ConfigurationProxy: PlatformItemSource { } } + private func trySave() { + if var manager = self.manager { + try? self.save(to: &manager) + } + } + func save(to manager: inout NETunnelProviderManager) throws { self.fix() if let data = self.data() { @@ -192,6 +256,18 @@ class ConfigurationProxy: PlatformItemSource { let disconnectrule = NEOnDemandRuleDisconnect() var rules: [NEOnDemandRule] = [disconnectrule] + if self.get("Any", inSection: "AutoStart") as? Bool ?? false { + let wifirule = NEOnDemandRuleConnect() + wifirule.interfaceTypeMatch = .any + rules.insert(wifirule, at: 0) + } + #if os(macOS) + if self.get("Ethernet", inSection: "AutoStart") as? Bool ?? false { + let wifirule = NEOnDemandRuleConnect() + wifirule.interfaceTypeMatch = .ethernet + rules.insert(wifirule, at: 0) + } + #endif if self.get("WiFi", inSection: "AutoStart") as? Bool ?? false { let wifirule = NEOnDemandRuleConnect() wifirule.interfaceTypeMatch = .wiFi @@ -214,8 +290,7 @@ class ConfigurationProxy: PlatformItemSource { if let error = error { print(error) } else { - print("Save successfully") - NotificationCenter.default.post(name: NSNotification.Name.YggdrasilSettingsUpdated, object: self) + print("Saved successfully") } }) } diff --git a/Yggdrasil Network Cross-Platform/CrossPlatformAppDelegate.swift b/Yggdrasil Network Cross-Platform/CrossPlatformAppDelegate.swift index 69f29f6..03cf897 100644 --- a/Yggdrasil Network Cross-Platform/CrossPlatformAppDelegate.swift +++ b/Yggdrasil Network Cross-Platform/CrossPlatformAppDelegate.swift @@ -22,46 +22,52 @@ typealias ApplicationDelegateAdaptor = NSApplicationDelegateAdaptor class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject { var vpnManager: NETunnelProviderManager = NETunnelProviderManager() + var yggdrasilConfig: ConfigurationProxy = ConfigurationProxy() let yggdrasilComponent = "eu.neilalexander.yggdrasil.extension" + private var adminTimer: DispatchSourceTimer? 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) + switch conn.status { + case .connected: + self.requestSummaryIPC() + self.requestStatusIPC() + case .disconnecting, .disconnected: + self.clearStatus() + default: + break + } } }) 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 + @Published var yggdrasilEnabled: Bool = false { + didSet { + if yggdrasilEnabled { + if vpnManager.connection.status != .connected && vpnManager.connection.status != .connecting { + do { + try self.vpnManager.connection.startVPNTunnel() + } catch { + print("Failed to start VPN tunnel: \(error.localizedDescription)") + return + } + } + } else { + if vpnManager.connection.status != .disconnected && vpnManager.connection.status != .disconnecting { + self.vpnManager.connection.stopVPNTunnel() + } } - 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 yggdrasilPublicKey: String = "N/A" @Published var yggdrasilIP: String = "N/A" @Published var yggdrasilSubnet: String = "N/A" @Published var yggdrasilCoords: String = "[]" @@ -74,39 +80,42 @@ class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject { return Yggdrasil.MobileGetVersion() } - func applicationDidBecomeActive(_ application: PlatformApplication) { + func becameActive() { print("Application became active") if self.adminTimer == nil { - self.adminTimer = DispatchSource.makeTimerSource(flags: .strict, queue: DispatchQueue(label: "Admin Queue")) + self.adminTimer = DispatchSource.makeTimerSource(flags: .strict, queue: .main) self.adminTimer!.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.seconds(2), leeway: DispatchTimeInterval.seconds(1)) self.adminTimer!.setEventHandler { - self.makeIPCRequests() + self.updateStatus(conn: self.vpnManager.connection) } } if self.adminTimer != nil { self.adminTimer!.resume() } + self.requestSummaryIPC() self.updateStatus(conn: self.vpnManager.connection) } - func updateStatus(conn: NEVPNConnection) { - if conn.status == .connected { - self.makeIPCRequests() - } 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: PlatformApplication) { + func becameInactive() { + print("Application became inactive") + if self.adminTimer != nil { self.adminTimer!.suspend() } } + func becameBackground() {} + + func updateStatus(conn: NEVPNConnection) { + if conn.status == .connected { + self.requestStatusIPC() + } else if conn.status == .disconnecting || conn.status == .disconnected { + self.clearStatus() + } + } + func vpnTunnelProviderManagerInit() { print("Loading saved managers...") @@ -138,25 +147,24 @@ class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject { } self.vpnManager.loadFromPreferences(completionHandler: { (error: Error?) in + var loadedConfig = false 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) { + if let loaded = try? ConfigurationProxy(json: confJson, manager: self.vpnManager) { print("Found existing protocol configuration") self.yggdrasilConfig = loaded + loadedConfig = true } else { print("Existing protocol configuration is invalid, ignoring") } } } - if self.yggdrasilConfig == nil { + if !loadedConfig { print("Generating new protocol configuration") - self.yggdrasilConfig = ConfigurationProxy() - - if let config = self.yggdrasilConfig { - try? config.save(to: &self.vpnManager) - } + self.yggdrasilConfig = ConfigurationProxy(manager: self.vpnManager) + try? self.yggdrasilConfig.save(to: &self.vpnManager) } self.vpnManager.localizedDescription = "Yggdrasil" @@ -165,56 +173,48 @@ class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject { } } - func makeIPCRequests() { + func requestSummaryIPC() { if self.vpnManager.connection.status != .connected { return } if let session = self.vpnManager.connection as? NETunnelProviderSession { - try? session.sendProviderMessage("address".data(using: .utf8)!) { (address) in - if let address = address { - self.yggdrasilIP = String(data: address, encoding: .utf8)! - NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil) + try? session.sendProviderMessage("summary".data(using: .utf8)!) { js in + if let js = js, let summary = try? JSONDecoder().decode(YggdrasilSummary.self, from: js) { + self.yggdrasilEnabled = true + self.yggdrasilIP = summary.address + self.yggdrasilSubnet = summary.subnet + self.yggdrasilPublicKey = summary.publicKey } } - try? session.sendProviderMessage("subnet".data(using: .utf8)!) { (subnet) in - if let subnet = subnet { - 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.yggdrasilCoords = String(data: coords, encoding: .utf8)! - NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil) - } - } - try? session.sendProviderMessage("peers".data(using: .utf8)!) { (peers) in - if let peers = peers { - if let jsonResponse = try? JSONSerialization.jsonObject(with: peers, options: []) as? [[String: Any]] { + } + } + + func requestStatusIPC() { + if self.vpnManager.connection.status != .connected { + return + } + if let session = self.vpnManager.connection as? NETunnelProviderSession { + try? session.sendProviderMessage("status".data(using: .utf8)!) { js in + if let js = js, let status = try? JSONDecoder().decode(YggdrasilStatus.self, from: js) { + self.yggdrasilCoords = status.coords + if let jsonResponse = try? JSONSerialization.jsonObject(with: status.peers, options: []) as? [[String: Any]] { self.yggdrasilPeers = jsonResponse - NotificationCenter.default.post(name: .YggdrasilPeersUpdated, object: nil) } - } - } - try? session.sendProviderMessage("dht".data(using: .utf8)!) { (peers) in - if let peers = peers { - if let jsonResponse = try? JSONSerialization.jsonObject(with: peers, options: []) as? [[String: Any]] { + if let jsonResponse = try? JSONSerialization.jsonObject(with: status.dht, options: []) as? [[String: Any]] { self.yggdrasilDHT = jsonResponse - NotificationCenter.default.post(name: .YggdrasilDHTUpdated, object: nil) } + self.yggdrasilConnected = self.yggdrasilEnabled && self.yggdrasilPeers.count > 0 && self.yggdrasilDHT.count > 0 } } } } func clearStatus() { + self.yggdrasilConnected = false self.yggdrasilIP = "N/A" self.yggdrasilSubnet = "N/A" self.yggdrasilCoords = "[]" self.yggdrasilPeers = [] self.yggdrasilDHT = [] - NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil) - NotificationCenter.default.post(name: .YggdrasilPeersUpdated, object: nil) - NotificationCenter.default.post(name: .YggdrasilDHTUpdated, object: nil) } } diff --git a/Yggdrasil Network Cross-Platform/IPCResponses.swift b/Yggdrasil Network Cross-Platform/IPCResponses.swift new file mode 100644 index 0000000..eb105cf --- /dev/null +++ b/Yggdrasil Network Cross-Platform/IPCResponses.swift @@ -0,0 +1,21 @@ +// +// IPCResponses.swift +// YggdrasilNetwork +// +// Created by Neil Alexander on 20/02/2019. +// + +import Foundation + +struct YggdrasilSummary: Codable { + var address: String + var subnet: String + var publicKey: String +} + +struct YggdrasilStatus: Codable { + var enabled: Bool + var coords: String + var peers: Data + var dht: Data +} diff --git a/Yggdrasil Network Cross-Platform/NSNotification.swift b/Yggdrasil Network Cross-Platform/NSNotification.swift deleted file mode 100644 index 075b14d..0000000 --- a/Yggdrasil Network Cross-Platform/NSNotification.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// NSNotification.swift -// YggdrasilNetwork -// -// Created by Neil Alexander on 20/02/2019. -// - -#if canImport(UIKit) -import UIKit -#elseif canImport(AppKit) -import AppKit -#endif - -extension Notification.Name { - static let YggdrasilSelfUpdated = Notification.Name("YggdrasilSelfUpdated") - static let YggdrasilPeersUpdated = Notification.Name("YggdrasilPeersUpdated") - static let YggdrasilSettingsUpdated = Notification.Name("YggdrasilSettingsUpdated") - static let YggdrasilDHTUpdated = Notification.Name("YggdrasilDHTUpdated") -} diff --git a/Yggdrasil Network Extension/PacketTunnelProvider.swift b/Yggdrasil Network Extension/PacketTunnelProvider.swift index e6d8fd7..f1d982a 100644 --- a/Yggdrasil Network Extension/PacketTunnelProvider.swift +++ b/Yggdrasil Network Extension/PacketTunnelProvider.swift @@ -55,6 +55,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { if let fd = self.tunnelFileDescriptor { do { try self.yggdrasil.takeOverTUN(fd) + NSLog("Yggdrasil taken over TUN successfully") } catch { NSLog("Taking over TUN produced an error: " + error.localizedDescription) err = error @@ -82,6 +83,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider { NSLog("Yggdrasil completion handler called") completionHandler(nil) } + } else { + NSLog("Error in Yggdrasil startTunnel: No configuration JSON found") } } } @@ -94,16 +97,27 @@ class PacketTunnelProvider: NEPacketTunnelProvider { override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) { let request = String(data: messageData, encoding: .utf8) switch request { - case "address": - completionHandler?(self.yggdrasil.getAddressString().data(using: .utf8)) - case "subnet": - completionHandler?(self.yggdrasil.getSubnetString().data(using: .utf8)) - case "coords": - completionHandler?(self.yggdrasil.getCoordsString().data(using: .utf8)) - case "peers": - completionHandler?(self.yggdrasil.getPeersJSON().data(using: .utf8)) - case "dht": - completionHandler?(self.yggdrasil.getDHTJSON().data(using: .utf8)) + case "summary": + let summary = YggdrasilSummary( + address: self.yggdrasil.getAddressString(), + subnet: self.yggdrasil.getSubnetString(), + publicKey: self.yggdrasil.getPublicKeyString() + ) + if let json = try? JSONEncoder().encode(summary) { + completionHandler?(json) + } + + case "status": + let status = YggdrasilStatus( + enabled: true, + coords: self.yggdrasil.getCoordsString(), + peers: self.yggdrasil.getPeersJSON().data(using: .utf8) ?? Data(), + dht: self.yggdrasil.getDHTJSON().data(using: .utf8) ?? Data() + ) + if let json = try? JSONEncoder().encode(status) { + completionHandler?(json) + } + default: completionHandler?(nil) } diff --git a/YggdrasilNetworkExtension.entitlements b/Yggdrasil Network Extension/YggdrasilNetworkExtension.entitlements similarity index 92% rename from YggdrasilNetworkExtension.entitlements rename to Yggdrasil Network Extension/YggdrasilNetworkExtension.entitlements index 9069017..9eb3cf1 100644 --- a/YggdrasilNetworkExtension.entitlements +++ b/Yggdrasil Network Extension/YggdrasilNetworkExtension.entitlements @@ -20,5 +20,7 @@ com.apple.security.network.client + com.apple.security.network.server + diff --git a/Yggdrasil Network iOS/Application/AppDelegate+AppDelegateExtension.h b/Yggdrasil Network iOS/Application/AppDelegate+AppDelegateExtension.h deleted file mode 100644 index 3809560..0000000 --- a/Yggdrasil Network iOS/Application/AppDelegate+AppDelegateExtension.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// AppDelegate+AppDelegateExtension.h -// Yggdrasil Network -// -// Created by Neil Alexander on 11/01/2019. -// - - - -NS_ASSUME_NONNULL_BEGIN - -@interface AppDelegate () - -@end - -NS_ASSUME_NONNULL_END diff --git a/Yggdrasil Network iOS/Application/AppDelegate.swift b/Yggdrasil Network iOS/Application/AppDelegate.swift deleted file mode 100644 index afc437d..0000000 --- a/Yggdrasil Network iOS/Application/AppDelegate.swift +++ /dev/null @@ -1,15 +0,0 @@ -import UIKit - -@UIApplicationMain -class AppDelegate: CrossPlatformAppDelegate { - var window: UIWindow? - - let configDir = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true)[0] - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch - self.vpnTunnelProviderManagerInit() - return true - } -} - diff --git a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index bef1a29..0000000 --- a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,104 +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" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "drawing copy-1.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "drawing copy.png", - "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" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "drawing copy-2.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "drawing copy-3.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "drawing copy-5.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "drawing copy-4.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-1.png b/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-1.png deleted file mode 100644 index eee5a75..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-1.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-2.png b/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-2.png deleted file mode 100644 index 567267c..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-2.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-3.png b/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-3.png deleted file mode 100644 index 42ab80b..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-3.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-4.png b/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-4.png deleted file mode 100644 index cc8b151..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-4.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-5.png b/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-5.png deleted file mode 100644 index d658df2..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy-5.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy.png b/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy.png deleted file mode 100644 index 720ec2e..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/AppIcon.appiconset/drawing copy.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/Contents.json b/Yggdrasil Network iOS/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164..0000000 --- a/Yggdrasil Network iOS/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/Contents.json b/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/Contents.json deleted file mode 100644 index 4e7019e..0000000 --- a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/Contents.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "images" : [ - { - "filename" : "img1.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "img1w.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "img2.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "img2w.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "img3.png", - "idiom" : "universal", - "scale" : "3x" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "img3w.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img1.png b/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img1.png deleted file mode 100644 index 99a5057..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img1.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img1w.png b/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img1w.png deleted file mode 100644 index f4cd7df..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img1w.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img2.png b/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img2.png deleted file mode 100644 index 5588c0f..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img2.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img2w.png b/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img2w.png deleted file mode 100644 index a8bd987..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img2w.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img3.png b/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img3.png deleted file mode 100644 index cf5a726..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img3.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img3w.png b/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img3w.png deleted file mode 100644 index 902eefd..0000000 Binary files a/Yggdrasil Network iOS/Assets.xcassets/YggdrasilNetwork.imageset/img3w.png and /dev/null differ diff --git a/Yggdrasil Network iOS/Extensions/Data.swift b/Yggdrasil Network iOS/Extensions/Data.swift deleted file mode 100644 index 39ef89a..0000000 --- a/Yggdrasil Network iOS/Extensions/Data.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// Data.swift -// YggdrasilNetworkExtension -// -// Created by Neil on 15/11/2022. -// - -import Foundation - -extension Data { - /// This computed value is only needed because of [this](https://github.com/golang/go/issues/33745) issue in the - /// golang/go repository. It is a workaround until the problem is solved upstream. - /// - /// The data object is converted into an array of bytes and than returned wrapped in an `NSMutableData` object. In - /// thas way Gomobile takes it as it is without copying. The Swift side remains responsible for garbage collection. - var mutable: Data { - var array = [UInt8](self) - return NSMutableData(bytes: &array, length: self.count) as Data - } - } diff --git a/Yggdrasil Network iOS/Extensions/UIDevice.swift b/Yggdrasil Network iOS/Extensions/UIDevice.swift deleted file mode 100644 index fb834e1..0000000 --- a/Yggdrasil Network iOS/Extensions/UIDevice.swift +++ /dev/null @@ -1,28 +0,0 @@ -import Foundation -import UIKit - -extension UIDevice { - /// A Boolean value indicating whether the device has cellular data capabilities (true) or not (false). - var hasCellularCapabilites: Bool { - var addrs: UnsafeMutablePointer? - var cursor: UnsafeMutablePointer? - - defer { freeifaddrs(addrs) } - - guard getifaddrs(&addrs) == 0 else { return false } - cursor = addrs - - while cursor != nil { - guard - let utf8String = cursor?.pointee.ifa_name, - let name = NSString(utf8String: utf8String), - name == "pdp_ip0" - else { - cursor = cursor?.pointee.ifa_next - continue - } - return true - } - return false - } -} diff --git a/Yggdrasil Network iOS/Info.plist b/Yggdrasil Network iOS/Info.plist deleted file mode 100644 index d7bbb57..0000000 --- a/Yggdrasil Network iOS/Info.plist +++ /dev/null @@ -1,69 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Yggdrasil - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 0.1 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - LSApplicationCategoryType - public.app-category.utilities - LSRequiresIPhoneOS - - LSSupportsOpeningDocumentsInPlace - - UIFileSharingEnabled - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - - UTExportedTypeDeclarations - - - UTTypeConformsTo - - public.text - - UTTypeDescription - Yggdrasil Configuration File - UTTypeIconFiles - - UTTypeIdentifier - eu.neilalexander.yggdrasil.configuration - UTTypeTagSpecification - - public.filename-extension - - yggconf - - - - - - diff --git a/Yggdrasil Network iOS/Storyboards/Base.lproj/LaunchScreen.storyboard b/Yggdrasil Network iOS/Storyboards/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f584721..0000000 --- a/Yggdrasil Network iOS/Storyboards/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Yggdrasil Network iOS/Storyboards/Base.lproj/Main.storyboard b/Yggdrasil Network iOS/Storyboards/Base.lproj/Main.storyboard deleted file mode 100644 index 69f6769..0000000 --- a/Yggdrasil Network iOS/Storyboards/Base.lproj/Main.storyboard +++ /dev/null @@ -1,674 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Configuration will be exported to the Files app. Your configuration contains your private key which is extremely sensitive. You must not share it with others. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Yggdrasil Network iOS/UI Components/CopyableLabel.swift b/Yggdrasil Network iOS/UI Components/CopyableLabel.swift deleted file mode 100644 index bd6fce0..0000000 --- a/Yggdrasil Network iOS/UI Components/CopyableLabel.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// CopyableLabel.swift -// YggdrasilNetwork -// -// Created by Neil Alexander on 26/02/2019. -// - -import UIKit - -class CopyableLabel: UILabel { - override public var canBecomeFirstResponder: Bool { - get { - return true - } - } - - override init(frame: CGRect) { - super.init(frame: frame) - self.isUserInteractionEnabled = true - self.addGestureRecognizer(UILongPressGestureRecognizer( - target: self, - action: #selector(showMenu(sender:)) - )) - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - self.isUserInteractionEnabled = true - self.addGestureRecognizer(UILongPressGestureRecognizer( - target: self, - action: #selector(showMenu(sender:)) - )) - } - - override func copy(_ sender: Any?) { - UIPasteboard.general.string = text - UIMenuController.shared.setMenuVisible(false, animated: true) - } - - @objc func showMenu(sender: Any?) { - self.becomeFirstResponder() - let menu = UIMenuController.shared - if !menu.isMenuVisible { - menu.setTargetRect(bounds, in: self) - menu.setMenuVisible(true, animated: true) - } - } - - override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { - return (action == #selector(copy(_:))) - } -} diff --git a/Yggdrasil Network iOS/UI Components/ToggleTableViewCell.swift b/Yggdrasil Network iOS/UI Components/ToggleTableViewCell.swift deleted file mode 100644 index 703782d..0000000 --- a/Yggdrasil Network iOS/UI Components/ToggleTableViewCell.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// ToggleTableViewCell.swift -// YggdrasilNetwork -// -// Created by Neil Alexander on 07/01/2019. -// - -import UIKit - -class ToggleTableViewCell: UITableViewCell { - - @IBOutlet weak var label: UILabel! - @IBOutlet weak var toggle: UISwitch! - - override func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } - -} diff --git a/Yggdrasil Network iOS/View Controllers/PeersViewController.swift b/Yggdrasil Network iOS/View Controllers/PeersViewController.swift deleted file mode 100644 index c7bca2c..0000000 --- a/Yggdrasil Network iOS/View Controllers/PeersViewController.swift +++ /dev/null @@ -1,286 +0,0 @@ -// -// PeersViewController.swift -// YggdrasilNetwork -// -// Created by Neil Alexander on 07/01/2019. -// - -import UIKit -import NetworkExtension -import CoreTelephony - -class PeersViewController: UITableViewController { - var app = UIApplication.shared.delegate as! AppDelegate - var config: [String: Any]? = nil - - @IBOutlet var peerTable: UITableView! - @IBOutlet weak var addButtonItem: UIBarButtonItem! - - override func viewDidLoad() { - super.viewDidLoad() - - if let proto = self.app.vpnManager.protocolConfiguration as? NETunnelProviderProtocol { - config = proto.providerConfiguration ?? nil - } - - self.navigationItem.rightBarButtonItems = [ - self.editButtonItem, - self.addButtonItem - ] - } - - override func viewWillAppear(_ animated: Bool) { - NotificationCenter.default.addObserver(self, selector: #selector(self.onYggdrasilPeersUpdated), name: NSNotification.Name.YggdrasilPeersUpdated, object: nil) - } - - override func viewWillDisappear(_ animated: Bool) { - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.YggdrasilPeersUpdated, object: nil) - } - - @objc func onYggdrasilPeersUpdated(notification: NSNotification) { - peerTable.reloadData() - } - - // MARK: - Table view data source - - override func numberOfSections(in tableView: UITableView) -> Int { - return 3 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch section { - case 0: return app.yggdrasilPeers.count - case 1: - if let config = self.app.yggdrasilConfig { - if let peers = config.get("Peers") as? [String] { - return peers.count - } - } - return 0 - case 2: - return 2 - default: return 0 - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch indexPath.section { - case 0: - let cell = tableView.dequeueReusableCell(withIdentifier: "discoveredPeerPrototype", for: indexPath) - let peers = app.yggdrasilPeers.sorted { (a, b) -> Bool in - return (a["Port"] as! Int) < (b["Port"] as! Int) - } - - if indexPath.row < peers.count { - let value = peers[indexPath.row] - let proto = value["Protocol"] as? String ?? "tcp" - let remote = value["Remote"] as? String ?? "unknown" - let prio = value["Priority"] as? Int ?? 0 - - cell.textLabel?.text = "\(value["IP"] ?? "(unknown)")" - cell.detailTextLabel?.text = "\(proto.uppercased()): \(remote)" - } - return cell - case 1: - let cell = tableView.dequeueReusableCell(withIdentifier: "configuredPeerPrototype", for: indexPath) - if let config = self.app.yggdrasilConfig { - if let peers = config.get("Peers") as? [String] { - cell.textLabel?.text = peers[indexPath.last!] - } else { - cell.textLabel?.text = "(unknown)" - } - } - return cell - case 2: - switch indexPath.last { - case 0: - let cell = tableView.dequeueReusableCell(withIdentifier: "togglePrototype", for: indexPath) as! ToggleTableViewCell - cell.isUserInteractionEnabled = true - cell.label?.text = "Discoverable over multicast" - cell.label?.isEnabled = true - cell.toggle?.addTarget(self, action: #selector(toggledMulticastBeacons), for: .valueChanged) - cell.toggle?.isEnabled = true - if let config = self.app.yggdrasilConfig { - cell.toggle?.isOn = config.multicastBeacons - } - return cell - case 1: - let cell = tableView.dequeueReusableCell(withIdentifier: "togglePrototype", for: indexPath) as! ToggleTableViewCell - cell.isUserInteractionEnabled = true - cell.label?.text = "Search for multicast peers" - cell.label?.isEnabled = true - cell.toggle?.addTarget(self, action: #selector(toggledMulticastListen), for: .valueChanged) - cell.toggle?.isEnabled = true - if let config = self.app.yggdrasilConfig { - cell.toggle?.isOn = config.multicastListen - } - return cell - default: - let cell = tableView.dequeueReusableCell(withIdentifier: "menuPrototype", for: indexPath) - cell.isUserInteractionEnabled = false - cell.textLabel?.text = "Unknown" - cell.textLabel?.isEnabled = true - return cell - } - default: - let cell = tableView.dequeueReusableCell(withIdentifier: "configuredPeerPrototype", for: indexPath) - cell.textLabel?.text = "(unknown)" - return cell - } - } - - func format(bytes: Double) -> String { - guard bytes > 0 else { - return "0 bytes" - } - - // Adapted from http://stackoverflow.com/a/18650828 - let suffixes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] - let k: Double = 1000 - let i = floor(log(bytes) / log(k)) - - // Format number with thousands separator and everything below 1 GB with no decimal places. - let numberFormatter = NumberFormatter() - numberFormatter.maximumFractionDigits = i < 3 ? 0 : 1 - numberFormatter.numberStyle = .decimal - - let numberString = numberFormatter.string(from: NSNumber(value: bytes / pow(k, i))) ?? "Unknown" - let suffix = suffixes[Int(i)] - return "\(numberString) \(suffix)" - } - - @objc func toggledMulticastBeacons(_ sender: UISwitch) { - if let config = self.app.yggdrasilConfig { - config.multicastBeacons = sender.isOn - try? config.save(to: &app.vpnManager) - } - } - - @objc func toggledMulticastListen(_ sender: UISwitch) { - if let config = self.app.yggdrasilConfig { - config.multicastListen = sender.isOn - try? config.save(to: &app.vpnManager) - } - } - - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch section { - case 0: - if self.app.yggdrasilPeers.count > 0 { - return "Connected Peers" - } - return "No peers currently connected" - case 1: - if let config = self.app.yggdrasilConfig { - if let peers = config.get("Peers") as? [String] { - if peers.count > 0 { - return "Configured Peers" - } - } - } - return "No peers currently configured" - case 2: - return "Peer Connectivity" - default: return "(Unknown)" - } - } - - override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - switch section { - case 1: - return "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." - case 2: - var str = "Multicast peers will be discovered on the same Wi-Fi network or via USB." - if UIDevice.current.hasCellularCapabilites { - str += " Data charges may apply when using mobile data. You can prevent mobile data usage in the device settings." - } - return str - default: return nil - } - } - - override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - return indexPath.first == 1 - } - - override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { - switch indexPath.first { - case 0: - return [UITableViewRowAction(style: UITableViewRowAction.Style.default, title: "Disconnect", handler: { (action, index) in - - })] - case 1: - return [UITableViewRowAction(style: UITableViewRowAction.Style.normal, title: "Remove", handler: { (action, index) in - print(action, index) - if let config = self.app.yggdrasilConfig { - config.remove(index: index.last!, from: "Peers") - do { - try config.save(to: &self.app.vpnManager) - tableView.reloadSections(IndexSet(integer: 1), with: UITableView.RowAnimation.automatic) - } catch { - let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) - self.parent?.present(alert, animated: true, completion: nil) - print("Error removing: \(error)") - } - } - })] - default: - return [] - } - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch indexPath.first { - case 2: - if let last = indexPath.last, last == 2 { - UIApplication.shared.open(NSURL(string:UIApplication.openSettingsURLString)! as URL, options: [:]) { (result) in - NSLog("Result " + result.description) - } - } - default: - break - } - tableView.deselectRow(at: indexPath, animated: true) - } - - @IBAction func addNewPeerButtonPressed(_ sender: UIBarButtonItem) { - let alert = UIAlertController(title: "Add Configured Peer", message: """ - Enter the full URI of the peer to add. Yggdrasil will automatically connect to this peer when started. - """, preferredStyle: UIAlertController.Style.alert) - let action = UIAlertAction(title: "Add", style: .default) { (alertAction) in - let textField = alert.textFields![0] as UITextField - if let text = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) { - if let config = self.app.yggdrasilConfig { - if let peers = config.get("Peers") as? [String], !peers.contains(text) { - config.add(text, in: "Peers") - do { - try config.save(to: &self.app.vpnManager) - if let index = config.get("Peers") as? [String] { - self.peerTable.insertRows(at: [IndexPath(indexes: [1, index.count-1])], with: .automatic) - self.peerTable.reloadSections(IndexSet(integer: 1), with: UITableView.RowAnimation.automatic) - } - } catch { - let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) - self.parent?.present(alert, animated: true, completion: nil) - print("Add error: \(error)") - } - } else { - let alert = UIAlertController(title: "Error", message: "Peer already exists", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) - self.parent?.present(alert, animated: true, completion: nil) - } - } - } - } - let cancel = UIAlertAction(title: "Cancel", style: .cancel) - alert.addTextField { (textField) in - textField.placeholder = "tcp://hostname:port" - } - alert.addAction(action) - alert.addAction(cancel) - self.present(alert, animated: true, completion: nil) - } - -} diff --git a/Yggdrasil Network iOS/View Controllers/SettingsViewController.swift b/Yggdrasil Network iOS/View Controllers/SettingsViewController.swift deleted file mode 100644 index 073d853..0000000 --- a/Yggdrasil Network iOS/View Controllers/SettingsViewController.swift +++ /dev/null @@ -1,135 +0,0 @@ -// -// SettingsTableViewController.swift -// YggdrasilNetwork -// -// Created by Neil Alexander on 03/01/2019. -// - -import UIKit -import NetworkExtension - -class SettingsViewController: UITableViewController, UIDocumentBrowserViewControllerDelegate { - var app = UIApplication.shared.delegate as! AppDelegate - - @IBOutlet weak var deviceNameField: UITextField! - - @IBOutlet weak var signingPublicKeyLabel: UILabel! - - @IBOutlet weak var autoStartWiFiCell: UITableViewCell! - @IBOutlet weak var autoStartMobileCell: UITableViewCell! - - override func viewDidLoad() { - super.viewDidLoad() - - if let config = self.app.yggdrasilConfig { - deviceNameField.text = config.get("name", inSection: "NodeInfo") as? String ?? "" - signingPublicKeyLabel.text = config.get("PublicKey") as? String ?? config.get("SigningPublicKey") as? String ?? "Unknown" - - autoStartWiFiCell.accessoryType = config.get("WiFi", inSection: "AutoStart") as? Bool ?? false ? .checkmark : .none - autoStartMobileCell.accessoryType = config.get("Mobile", inSection: "AutoStart") as? Bool ?? false ? .checkmark : .none - } - } - - @IBAction func deviceNameEdited(_ sender: UITextField) { - if let config = self.app.yggdrasilConfig { - config.set("name", inSection: "NodeInfo", to: sender.text) - try? config.save(to: &app.vpnManager) - } - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch indexPath.first { - case 1: - let settings = [ - "WiFi", - "Mobile" - ] - if let cell = tableView.cellForRow(at: indexPath) { - cell.accessoryType = cell.accessoryType == .checkmark ? .none : .checkmark - if let config = self.app.yggdrasilConfig { - config.set(settings[indexPath.last!], inSection: "AutoStart", to: cell.accessoryType == .checkmark) - try? config.save(to: &app.vpnManager) - } - } - case 3: - switch indexPath.last { - case 0: // import - if #available(iOS 11.0, *) { - let open = UIDocumentBrowserViewController(forOpeningFilesWithContentTypes: ["eu.neilalexander.yggdrasil.configuration"]) - open.delegate = self - open.allowsDocumentCreation = false - open.allowsPickingMultipleItems = false - open.additionalTrailingNavigationBarButtonItems = [ UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelDocumentBrowser)) ] - self.present(open, animated: true, completion: nil) - } else { - let alert = UIAlertController(title: "Import Configuration", message: "Not supported on this version of iOS!", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) - self.present(alert, animated: true, completion: nil) - } - case 1: // export - if let config = self.app.yggdrasilConfig, let data = config.data() { - var fileURL: URL? - var fileDir: URL? - do { - let dateFormatter = DateFormatter() - dateFormatter.locale = Locale(identifier: "en_US_POSIX") - dateFormatter.dateFormat = "yyyy-MM-dd" - let date = dateFormatter.string(from: Date()) - fileDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) - fileURL = fileDir?.appendingPathComponent("Yggdrasil Backup \(date).yggconf") - try? data.write(to: fileURL!) - } catch { - break - } - if let dir = fileDir { - let sharedurl = dir.absoluteString.replacingOccurrences(of: "file://", with: "shareddocuments://") - let furl: URL = URL(string: sharedurl)! - UIApplication.shared.open(furl, options: [:], completionHandler: nil) - } - } - default: - break - } - case 4: - let alert = UIAlertController(title: "Warning", message: "This operation will reset your configuration and generate new keys. This is not reversible unless your configuration has been exported. Changes will not take effect until the next time Yggdrasil is restarted.", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "Reset", style: .destructive, handler: { action in - self.app.yggdrasilConfig = ConfigurationProxy() - if let config = self.app.yggdrasilConfig { - try? config.save(to: &self.app.vpnManager) - self.viewDidLoad() - }})) - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) - self.present(alert, animated: true, completion: nil) - default: - break - } - tableView.deselectRow(at: indexPath, animated: true) - } - - @objc func cancelDocumentBrowser() { - self.dismiss(animated: true, completion: nil) - } - - func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL]) { - do { - if let url = documentURLs.first { - let data = try Data(contentsOf: url) - let conf = try ConfigurationProxy(json: data) - try conf.save(to: &self.app.vpnManager) - self.app.yggdrasilConfig = conf - - controller.dismiss(animated: true, completion: nil) - let alert = UIAlertController(title: "Import Configuration", message: "Configuration file has been imported.", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) - self.present(alert, animated: true, completion: nil) - } - } catch { - controller.dismiss(animated: true, completion: nil) - let alert = UIAlertController(title: "Import Failed", message: "Unable to import this configuration file.", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) - self.present(alert, animated: true, completion: nil) - } - self.viewDidLoad() - } - -} diff --git a/Yggdrasil Network iOS/View Controllers/SplitViewController.swift b/Yggdrasil Network iOS/View Controllers/SplitViewController.swift deleted file mode 100644 index 4149fd3..0000000 --- a/Yggdrasil Network iOS/View Controllers/SplitViewController.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// SplitViewController.swift -// YggdrasilNetwork -// -// Created by Neil Alexander on 02/01/2019. -// - -import UIKit - -class SplitViewController: UISplitViewController, UISplitViewControllerDelegate { - - override func viewDidLoad() { - super.viewDidLoad() - self.delegate = self - self.preferredDisplayMode = .allVisible - } - - func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool { - return true - } - - @available(iOS 14.0,*) - func splitViewController(_ svc: UISplitViewController, topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column) -> UISplitViewController.Column { - return .primary - } - -} diff --git a/Yggdrasil Network iOS/View Controllers/TableViewController.swift b/Yggdrasil Network iOS/View Controllers/TableViewController.swift deleted file mode 100644 index 5de6b2a..0000000 --- a/Yggdrasil Network iOS/View Controllers/TableViewController.swift +++ /dev/null @@ -1,137 +0,0 @@ -import UIKit -import NetworkExtension -import Yggdrasil - -class TableViewController: UITableViewController { - var app = UIApplication.shared.delegate as! AppDelegate - - @IBOutlet var connectedStatusLabel: UILabel! - - @IBOutlet var toggleTableView: UITableView! - @IBOutlet var toggleLabel: UILabel! - @IBOutlet var toggleConnect: UISwitch! - - @IBOutlet weak var statsSelfIPCell: UITableViewCell! - @IBOutlet weak var statsSelfSubnetCell: UITableViewCell! - @IBOutlet weak var statsSelfCoordsCell: UITableViewCell! - - @IBOutlet var statsSelfIP: UILabel! - @IBOutlet var statsSelfSubnet: UILabel! - @IBOutlet var statsSelfCoords: UILabel! - @IBOutlet var statsSelfPeers: UILabel! - - @IBOutlet var statsVersion: UILabel! - - override func viewDidLoad() { - NotificationCenter.default.addObserver(self, selector: #selector(self.onYggdrasilSelfUpdated), name: NSNotification.Name.YggdrasilSelfUpdated, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(self.onYggdrasilPeersUpdated), name: NSNotification.Name.YggdrasilPeersUpdated, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(self.onYggdrasilDHTUpdated), name: NSNotification.Name.YggdrasilDHTUpdated, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(self.onYggdrasilSettingsUpdated), name: NSNotification.Name.YggdrasilSettingsUpdated, object: nil) - } - - @IBAction func onRefreshButton(_ sender: UIButton) { - sender.isEnabled = false - app.makeIPCRequests() - sender.isEnabled = true - } - - override func viewWillAppear(_ animated: Bool) { - //NotificationCenter.default.addObserver(self, selector: #selector(TableViewController.VPNStatusDidChange(_:)), name: NSNotification.Name.NEVPNStatusDidChange, object: nil) - - if let row = self.tableView.indexPathForSelectedRow { - self.tableView.deselectRow(at: row, animated: true) - } - - self.statsVersion.text = Yggdrasil.MobileGetVersion() - } - - override func viewWillDisappear(_ animated: Bool) { - //NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NEVPNStatusDidChange, object: nil) - } - - override func viewDidAppear(_ animated: Bool) { - self.onYggdrasilSelfUpdated(notification: NSNotification.init(name: NSNotification.Name.YggdrasilSettingsUpdated, object: nil)) - } - - override func viewWillLayoutSubviews() { - self.onYggdrasilSelfUpdated(notification: NSNotification.init(name: NSNotification.Name.YggdrasilSettingsUpdated, object: nil)) - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - if let row = self.tableView.indexPathForSelectedRow { - self.tableView.deselectRow(at: row, animated: true) - } - } - - @objc func onYggdrasilSettingsUpdated(notification: NSNotification) { - toggleLabel.isEnabled = !app.vpnManager.isOnDemandEnabled - toggleConnect.isEnabled = !app.vpnManager.isOnDemandEnabled - - if let footer = toggleTableView.footerView(forSection: 0) { - if let label = footer.textLabel { - label.text = app.vpnManager.isOnDemandEnabled ? "Yggdrasil is configured to automatically start and stop based on available connectivity." : "Yggdrasil is configured to start and stop manually." - } - } - } - - func updateConnectedStatus() { - if self.app.vpnManager.connection.status == .connected { - if app.yggdrasilDHT.count > 0 { - connectedStatusLabel.text = "Enabled" - connectedStatusLabel.textColor = UIColor(red: 0.37, green: 0.79, blue: 0.35, alpha: 1.0) - } else { - connectedStatusLabel.text = "No connectivity" - connectedStatusLabel.textColor = UIColor.red - } - } else { - connectedStatusLabel.text = "Not enabled" - connectedStatusLabel.textColor = UIColor.systemGray - } - } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - } - - @objc func onYggdrasilSelfUpdated(notification: NSNotification) { - statsSelfIP.text = app.yggdrasilIP - statsSelfSubnet.text = app.yggdrasilSubnet - statsSelfCoords.text = app.yggdrasilCoords - - statsSelfIPCell.layoutSubviews() - statsSelfSubnetCell.layoutSubviews() - statsSelfCoordsCell.layoutSubviews() - - let status = self.app.vpnManager.connection.status - toggleConnect.isOn = status == .connecting || status == .connected - - self.updateConnectedStatus() - } - - @objc func onYggdrasilDHTUpdated(notification: NSNotification) { - self.updateConnectedStatus() - } - - @objc func onYggdrasilPeersUpdated(notification: NSNotification) { - let peercount = app.yggdrasilPeers.count - if peercount <= 0 { - statsSelfPeers.text = "No peers" - } else if peercount == 1 { - statsSelfPeers.text = "\(peercount) peer" - } else { - statsSelfPeers.text = "\(peercount) peers" - } - } - - @IBAction func toggleVPNStatus(_ sender: UISwitch, forEvent event: UIEvent) { - if sender.isOn { - do { - try self.app.vpnManager.connection.startVPNTunnel() - } catch { - print(error) - } - } else { - self.app.vpnManager.connection.stopVPNTunnel() - } - } -} diff --git a/Yggdrasil Network.xcodeproj/project.pbxproj b/Yggdrasil Network.xcodeproj/project.pbxproj index f491495..4db300f 100644 --- a/Yggdrasil Network.xcodeproj/project.pbxproj +++ b/Yggdrasil Network.xcodeproj/project.pbxproj @@ -3,72 +3,54 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 55; objects = { /* Begin PBXBuildFile section */ - 3913E9C021DD3A51001E0EC7 /* SplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3913E9BF21DD3A51001E0EC7 /* SplitViewController.swift */; }; 391B72A82A2FD90100896278 /* PacketTunnelProvider+FileDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 391B72A62A2FD90100896278 /* PacketTunnelProvider+FileDescriptor.swift */; }; - 3939196B21E35A7C009320F3 /* PeersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3939196A21E35A7C009320F3 /* PeersViewController.swift */; }; - 3939196D21E39313009320F3 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3939196C21E39313009320F3 /* UIDevice.swift */; }; - 3939197321E39815009320F3 /* ToggleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3939197221E39815009320F3 /* ToggleTableViewCell.swift */; }; - 394A1EB321DEA46400D9F553 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 394A1EB221DEA46400D9F553 /* SettingsViewController.swift */; }; - 3952ADB729945AF700B3835D /* ConfigurationProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3952ADB629945AF700B3835D /* ConfigurationProxy.swift */; }; 3952ADB829945AF700B3835D /* ConfigurationProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3952ADB629945AF700B3835D /* ConfigurationProxy.swift */; }; - 3952ADBA29945AFA00B3835D /* CrossPlatformAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3952ADB929945AFA00B3835D /* CrossPlatformAppDelegate.swift */; }; - 39682A392225AD15004FB670 /* CopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39682A382225AD15004FB670 /* CopyableLabel.swift */; }; - 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 */; }; + 39B51A4D299951D60059D29D /* IPCResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CC924B221DEDCE004960DC /* IPCResponses.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 */; }; + 39CC924D221DEDD3004960DC /* IPCResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CC924B221DEDCE004960DC /* IPCResponses.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 */; }; - E593CE761DF8FC3C00D7265D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E593CE751DF8FC3C00D7265D /* Assets.xcassets */; }; - E593CE791DF8FC3C00D7265D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E593CE771DF8FC3C00D7265D /* LaunchScreen.storyboard */; }; + 39F99B342A48F6E50045BD10 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39AE88382319C93F0010FFF6 /* NetworkExtension.framework */; }; + 39F99B382A48F74F0045BD10 /* YggdrasilNetworkExtension.appex in CopyFiles */ = {isa = PBXBuildFile; fileRef = E593CE971DF905AF00D7265D /* YggdrasilNetworkExtension.appex */; platformFilters = (ios, macos, ); settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; E593CE9C1DF905AF00D7265D /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E593CE9B1DF905AF00D7265D /* PacketTunnelProvider.swift */; }; - E593CEA01DF905AF00D7265D /* YggdrasilNetworkExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E593CE971DF905AF00D7265D /* YggdrasilNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - E593CE9E1DF905AF00D7265D /* PBXContainerItemProxy */ = { + 39F99B352A48F70F0045BD10 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E593CE631DF8FC3C00D7265D /* Project object */; proxyType = 1; remoteGlobalIDString = E593CE961DF905AF00D7265D; - remoteInfo = NEPacketTunnelVPNDemoTunnel; + remoteInfo = YggdrasilNetworkExtension; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - E593CEA41DF905B000D7265D /* Embed Foundation Extensions */ = { + 39F99B372A48F7380045BD10 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 13; files = ( - E593CEA01DF905AF00D7265D /* YggdrasilNetworkExtension.appex in Embed Foundation Extensions */, + 39F99B382A48F74F0045BD10 /* YggdrasilNetworkExtension.appex in CopyFiles */, ); - name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 3913E99C21DB9B1C001E0EC7 /* YggdrasilNetworkExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = YggdrasilNetworkExtension.entitlements; sourceTree = ""; }; - 3913E99E21DB9B41001E0EC7 /* YggdrasilNetwork.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = YggdrasilNetwork.entitlements; sourceTree = ""; }; 3913E9BF21DD3A51001E0EC7 /* SplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitViewController.swift; sourceTree = ""; }; 391B72A52A2FD90100896278 /* PacketTunnelProvider+FileDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PacketTunnelProvider+FileDescriptor.h"; sourceTree = ""; }; 391B72A62A2FD90100896278 /* PacketTunnelProvider+FileDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PacketTunnelProvider+FileDescriptor.swift"; sourceTree = ""; }; @@ -84,9 +66,7 @@ 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 = ""; }; 39BF9FC12A2E9E51000E7269 /* YggdrasilNetworkExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "YggdrasilNetworkExtension-Bridging-Header.h"; sourceTree = ""; }; - 39BF9FC22A2E9E52000E7269 /* PacketTunnelProvider+FileDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PacketTunnelProvider+FileDescriptor.h"; sourceTree = ""; }; - 39BF9FC52A2F5FA7000E7269 /* PacketTunnelProvider+FileDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PacketTunnelProvider+FileDescriptor.swift"; sourceTree = ""; }; - 39CC924B221DEDCE004960DC /* NSNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSNotification.swift; sourceTree = ""; }; + 39CC924B221DEDCE004960DC /* IPCResponses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPCResponses.swift; sourceTree = ""; }; 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 = ""; }; 39F0205F2996CD760093F603 /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = ""; }; @@ -94,7 +74,6 @@ 39F020632996CD770093F603 /* YggdrasilSwiftUI.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = YggdrasilSwiftUI.entitlements; sourceTree = ""; }; 39F020652996CD770093F603 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 39F0206A2996CF260093F603 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; - 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 = ""; }; E593CE701DF8FC3C00D7265D /* TableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; E593CE731DF8FC3C00D7265D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -111,19 +90,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 39F99B342A48F6E50045BD10 /* NetworkExtension.framework in Frameworks */, 39BF9FC72A2F6FFD000E7269 /* Yggdrasil.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - E593CE681DF8FC3C00D7265D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3996AF38270328080070947D /* Yggdrasil.xcframework in Frameworks */, - 39AE88392319C93F0010FFF6 /* NetworkExtension.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; E593CE941DF905AF00D7265D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -185,7 +156,7 @@ children = ( 3952ADB929945AFA00B3835D /* CrossPlatformAppDelegate.swift */, 3952ADB629945AF700B3835D /* ConfigurationProxy.swift */, - 39CC924B221DEDCE004960DC /* NSNotification.swift */, + 39CC924B221DEDCE004960DC /* IPCResponses.swift */, ); name = "Yggdrasil Network Core"; path = "Yggdrasil Network Cross-Platform"; @@ -226,8 +197,6 @@ isa = PBXGroup; children = ( 3952ADB529945AE900B3835D /* Yggdrasil Network Core */, - 3913E99E21DB9B41001E0EC7 /* YggdrasilNetwork.entitlements */, - 3913E99C21DB9B1C001E0EC7 /* YggdrasilNetworkExtension.entitlements */, E593CE981DF905AF00D7265D /* Yggdrasil Network Extension */, E593CE6D1DF8FC3C00D7265D /* Yggdrasil Network iOS */, 39F0205C2996CD760093F603 /* YggdrasilSwiftUI */, @@ -239,7 +208,6 @@ E593CE6C1DF8FC3C00D7265D /* Products */ = { isa = PBXGroup; children = ( - E593CE6B1DF8FC3C00D7265D /* YggdrasilNetwork.app */, E593CE971DF905AF00D7265D /* YggdrasilNetworkExtension.appex */, 39F0205B2996CD760093F603 /* YggdrasilSwiftUI.app */, ); @@ -266,6 +234,7 @@ E593CE9B1DF905AF00D7265D /* PacketTunnelProvider.swift */, 391B72A52A2FD90100896278 /* PacketTunnelProvider+FileDescriptor.h */, 391B72A62A2FD90100896278 /* PacketTunnelProvider+FileDescriptor.swift */, + 3913E99C21DB9B1C001E0EC7 /* YggdrasilNetworkExtension.entitlements */, 391B72A72A2FD90100896278 /* YggdrasilNetworkExtension-Bridging-Header.h */, E593CE9D1DF905AF00D7265D /* Info.plist */, 39BF9FC12A2E9E51000E7269 /* YggdrasilNetworkExtension-Bridging-Header.h */, @@ -283,35 +252,18 @@ 39F020572996CD760093F603 /* Sources */, 39F020582996CD760093F603 /* Frameworks */, 39F020592996CD760093F603 /* Resources */, + 39F99B372A48F7380045BD10 /* CopyFiles */, ); buildRules = ( ); dependencies = ( + 39F99B362A48F70F0045BD10 /* PBXTargetDependency */, ); 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" */; - buildPhases = ( - E593CE671DF8FC3C00D7265D /* Sources */, - E593CE681DF8FC3C00D7265D /* Frameworks */, - E593CE691DF8FC3C00D7265D /* Resources */, - E593CEA41DF905B000D7265D /* Embed Foundation Extensions */, - ); - buildRules = ( - ); - dependencies = ( - E593CE9F1DF905AF00D7265D /* PBXTargetDependency */, - ); - name = YggdrasilNetwork; - productName = NEPacketTunnelVPNDemo; - productReference = E593CE6B1DF8FC3C00D7265D /* YggdrasilNetwork.app */; - productType = "com.apple.product-type.application"; - }; E593CE961DF905AF00D7265D /* YggdrasilNetworkExtension */ = { isa = PBXNativeTarget; buildConfigurationList = E593CEA31DF905AF00D7265D /* Build configuration list for PBXNativeTarget "YggdrasilNetworkExtension" */; @@ -335,31 +287,14 @@ E593CE631DF8FC3C00D7265D /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1420; - LastUpgradeCheck = 1420; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 39F0205A2996CD760093F603 = { CreatedOnToolsVersion = 14.2; }; - E593CE6A1DF8FC3C00D7265D = { - CreatedOnToolsVersion = 8.1; - LastSwiftMigration = 1030; - SystemCapabilities = { - com.apple.ApplicationGroups.iOS = { - enabled = 1; - }; - com.apple.NetworkExtensions.iOS = { - enabled = 1; - }; - com.apple.VPNLite = { - enabled = 1; - }; - com.apple.iCloud = { - enabled = 0; - }; - }; - }; E593CE961DF905AF00D7265D = { CreatedOnToolsVersion = 8.1; LastSwiftMigration = 1430; @@ -390,7 +325,6 @@ projectDirPath = ""; projectRoot = ""; targets = ( - E593CE6A1DF8FC3C00D7265D /* YggdrasilNetwork */, E593CE961DF905AF00D7265D /* YggdrasilNetworkExtension */, 39F0205A2996CD760093F603 /* YggdrasilSwiftUI */, ); @@ -407,16 +341,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - E593CE691DF8FC3C00D7265D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E593CE791DF8FC3C00D7265D /* LaunchScreen.storyboard in Resources */, - E593CE761DF8FC3C00D7265D /* Assets.xcassets in Resources */, - E593CE741DF8FC3C00D7265D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; E593CE951DF905AF00D7265D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -435,35 +359,17 @@ 39F0206B2996CF260093F603 /* SettingsView.swift in Sources */, 39B51A4A2997062E0059D29D /* PeersView.swift in Sources */, 39F020602996CD760093F603 /* StatusView.swift in Sources */, - 39B51A4D299951D60059D29D /* NSNotification.swift in Sources */, + 39B51A4D299951D60059D29D /* IPCResponses.swift in Sources */, 39B51A4C29994F350059D29D /* CrossPlatformAppDelegate.swift in Sources */, 39F0205E2996CD760093F603 /* Application.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - E593CE671DF8FC3C00D7265D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3939196B21E35A7C009320F3 /* PeersViewController.swift in Sources */, - 3939197321E39815009320F3 /* ToggleTableViewCell.swift in Sources */, - 3939196D21E39313009320F3 /* UIDevice.swift in Sources */, - 394A1EB321DEA46400D9F553 /* SettingsViewController.swift in Sources */, - E593CE711DF8FC3C00D7265D /* TableViewController.swift in Sources */, - 3952ADBA29945AFA00B3835D /* CrossPlatformAppDelegate.swift in Sources */, - 3952ADB729945AF700B3835D /* ConfigurationProxy.swift in Sources */, - 39682A392225AD15004FB670 /* CopyableLabel.swift in Sources */, - E593CE6F1DF8FC3C00D7265D /* AppDelegate.swift in Sources */, - 3913E9C021DD3A51001E0EC7 /* SplitViewController.swift in Sources */, - 39CC924C221DEDCE004960DC /* NSNotification.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; E593CE931DF905AF00D7265D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 39CC924D221DEDD3004960DC /* NSNotification.swift in Sources */, + 39CC924D221DEDD3004960DC /* IPCResponses.swift in Sources */, E593CE9C1DF905AF00D7265D /* PacketTunnelProvider.swift in Sources */, 3952ADB829945AF700B3835D /* ConfigurationProxy.swift in Sources */, 391B72A82A2FD90100896278 /* PacketTunnelProvider+FileDescriptor.swift in Sources */, @@ -473,10 +379,14 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - E593CE9F1DF905AF00D7265D /* PBXTargetDependency */ = { + 39F99B362A48F70F0045BD10 /* PBXTargetDependency */ = { isa = PBXTargetDependency; + platformFilters = ( + ios, + macos, + ); target = E593CE961DF905AF00D7265D /* YggdrasilNetworkExtension */; - targetProxy = E593CE9E1DF905AF00D7265D /* PBXContainerItemProxy */; + targetProxy = 39F99B352A48F70F0045BD10 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -505,6 +415,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_OBJC_WEAK = YES; @@ -512,12 +423,14 @@ CODE_SIGN_ENTITLEMENTS = YggdrasilSwiftUI/YggdrasilSwiftUI.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; 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_CFBundleDisplayName = Yggdrasil; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; @@ -535,13 +448,16 @@ MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = eu.neilalexander.yggdrasil.YggdrasilSwiftUI; + PRODUCT_BUNDLE_IDENTIFIER = eu.neilalexander.yggdrasil; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + TVOS_DEPLOYMENT_TARGET = 16.0; }; name = Debug; }; @@ -550,6 +466,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_OBJC_WEAK = YES; @@ -557,12 +474,14 @@ CODE_SIGN_ENTITLEMENTS = YggdrasilSwiftUI/YggdrasilSwiftUI.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; 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_CFBundleDisplayName = Yggdrasil; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; @@ -579,13 +498,16 @@ MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = eu.neilalexander.yggdrasil.YggdrasilSwiftUI; + PRODUCT_BUNDLE_IDENTIFIER = eu.neilalexander.yggdrasil; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + TVOS_DEPLOYMENT_TARGET = 16.0; }; name = Release; }; @@ -711,72 +633,6 @@ }; name = Release; }; - E593CE7E1DF8FC3C00D7265D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = YggdrasilNetwork.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 32; - DEVELOPMENT_TEAM = R9AV23TXF2; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - ); - INFOPLIST_FILE = "$(SRCROOT)/Yggdrasil Network iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = eu.neilalexander.yggdrasil; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - STRIP_INSTALLED_PRODUCT = NO; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - E593CE7F1DF8FC3C00D7265D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = YggdrasilNetwork.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 32; - DEVELOPMENT_TEAM = R9AV23TXF2; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - ); - INFOPLIST_FILE = "$(SRCROOT)/Yggdrasil Network iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = eu.neilalexander.yggdrasil; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; E593CEA11DF905AF00D7265D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -801,7 +657,6 @@ PRODUCT_BUNDLE_IDENTIFIER = eu.neilalexander.yggdrasil.extension; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - STRIP_INSTALLED_PRODUCT = NO; SUPPORTS_MACCATALYST = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_OBJC_BRIDGING_HEADER = "Yggdrasil Network Extension/YggdrasilNetworkExtension-Bridging-Header.h"; @@ -864,15 +719,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - E593CE7D1DF8FC3C00D7265D /* Build configuration list for PBXNativeTarget "YggdrasilNetwork" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E593CE7E1DF8FC3C00D7265D /* Debug */, - E593CE7F1DF8FC3C00D7265D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; E593CEA31DF905AF00D7265D /* Build configuration list for PBXNativeTarget "YggdrasilNetworkExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Yggdrasil Network.xcodeproj/xcshareddata/xcschemes/YggdrasilNetwork.xcscheme b/Yggdrasil Network.xcodeproj/xcshareddata/xcschemes/YggdrasilNetwork.xcscheme index d512f1b..2bda722 100644 --- a/Yggdrasil Network.xcodeproj/xcshareddata/xcschemes/YggdrasilNetwork.xcscheme +++ b/Yggdrasil Network.xcodeproj/xcshareddata/xcschemes/YggdrasilNetwork.xcscheme @@ -1,6 +1,6 @@ diff --git a/Yggdrasil.xcframework/Info.plist b/Yggdrasil.xcframework/Info.plist new file mode 100644 index 0000000..bc7e6bb --- /dev/null +++ b/Yggdrasil.xcframework/Info.plist @@ -0,0 +1,68 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + Yggdrasil.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + Yggdrasil.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + LibraryIdentifier + ios-arm64 + LibraryPath + Yggdrasil.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + Yggdrasil.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/YggdrasilNetwork.entitlements b/YggdrasilNetwork.entitlements deleted file mode 100644 index ae10342..0000000 --- a/YggdrasilNetwork.entitlements +++ /dev/null @@ -1,22 +0,0 @@ - - - - - com.apple.developer.networking.networkextension - - packet-tunnel-provider - - com.apple.developer.networking.vpn.api - - allow-vpn - - com.apple.security.app-sandbox - - com.apple.security.application-groups - - group.eu.neilalexander.yggdrasil - - com.apple.security.network.client - - - diff --git a/YggdrasilSwiftUI/Application.swift b/YggdrasilSwiftUI/Application.swift index 98e2330..45f54bb 100644 --- a/YggdrasilSwiftUI/Application.swift +++ b/YggdrasilSwiftUI/Application.swift @@ -10,20 +10,21 @@ import NetworkExtension @main struct Application: App { + @State private var selection: String? = "Status" + #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() - + @Environment(\.scenePhase) var scenePhase + var body: some Scene { WindowGroup { NavigationSplitView { List(selection: $selection) { - NavigationLink(destination: StatusView(yggdrasilConfiguration: $config)) { + NavigationLink(destination: StatusView()) { HStack { Image(systemName: "info.circle") .foregroundColor(.accentColor) @@ -50,11 +51,30 @@ struct Application: App { } .listStyle(.sidebar) .navigationSplitViewColumnWidth(200) + + Image("YggdrasilLogo") + .resizable() + .aspectRatio(contentMode: .fit) + .foregroundColor(.primary) + .opacity(0.1) + .padding(.all, 24.0) } detail: { - StatusView(yggdrasilConfiguration: $config) + StatusView() } .navigationTitle("Yggdrasil") .navigationSplitViewStyle(.automatic) + .onChange(of: scenePhase) { phase in + switch phase { + case .background: + Application.appDelegate.becameBackground() + case .inactive: + Application.appDelegate.becameInactive() + case .active: + Application.appDelegate.becameActive() + @unknown default: + break + } + } } #if os(macOS) .windowStyle(.hiddenTitleBar) diff --git a/YggdrasilSwiftUI/Assets.xcassets/AccentColor.colorset/Contents.json b/YggdrasilSwiftUI/Assets.xcassets/AccentColor.colorset/Contents.json index eb87897..f78f450 100644 --- a/YggdrasilSwiftUI/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/YggdrasilSwiftUI/Assets.xcassets/AccentColor.colorset/Contents.json @@ -1,6 +1,33 @@ { "colors" : [ { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.522", + "green" : "0.656", + "red" : "0.370" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.718", + "green" : "0.896", + "red" : "0.514" + } + }, "idiom" : "universal" } ], diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/Contents.json b/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/Contents.json deleted file mode 100644 index 96c6335..0000000 --- a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/Contents.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "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 - } -} diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-1.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-1.png deleted file mode 100644 index eee5a75..0000000 Binary files a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-1.png and /dev/null differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-2.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-2.png deleted file mode 100644 index 567267c..0000000 Binary files a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-2.png and /dev/null differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-3.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-3.png deleted file mode 100644 index 42ab80b..0000000 Binary files a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-3.png and /dev/null differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-4.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-4.png deleted file mode 100644 index cc8b151..0000000 Binary files a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-4.png and /dev/null differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-5.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-5.png deleted file mode 100644 index d658df2..0000000 Binary files a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy-5.png and /dev/null differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy.png deleted file mode 100644 index 720ec2e..0000000 Binary files a/YggdrasilSwiftUI/Assets.xcassets/AppIcon 1.appiconset/drawing copy.png and /dev/null differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/Contents.json b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/Contents.json index 4df0353..3e7a827 100644 --- a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,58 +1,73 @@ { "images" : [ { - "filename" : "drawing copy-4 1.png", + "filename" : "icon_512x512@2x 1.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" }, { + "filename" : "icon-1024.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "filename" : "icon_16x16.png", "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, { + "filename" : "icon_16x16@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, { + "filename" : "icon_32x32.png", "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, { + "filename" : "icon_32x32@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, { + "filename" : "icon_128x128.png", "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, { + "filename" : "icon_128x128@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, { + "filename" : "icon_256x256.png", "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { + "filename" : "icon_256x256@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, { + "filename" : "icon_512x512 1.png", "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, { - "filename" : "drawing copy-4.png", + "filename" : "icon_512x512@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "512x512" diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/drawing copy-4 1.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/drawing copy-4 1.png deleted file mode 100644 index cc8b151..0000000 Binary files a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/drawing copy-4 1.png and /dev/null differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/drawing copy-4.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/drawing copy-4.png deleted file mode 100644 index cc8b151..0000000 Binary files a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/drawing copy-4.png and /dev/null differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon-1024.png new file mode 100644 index 0000000..d5e9e4c Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon-1024.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_128x128.png new file mode 100644 index 0000000..77b1a41 Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_128x128.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png new file mode 100644 index 0000000..5b76fd6 Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_16x16.png new file mode 100644 index 0000000..6a6c2c4 Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_16x16.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png new file mode 100644 index 0000000..f7684c2 Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_256x256.png new file mode 100644 index 0000000..5b76fd6 Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_256x256.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png new file mode 100644 index 0000000..f64fcd6 Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_32x32.png new file mode 100644 index 0000000..f7684c2 Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_32x32.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png new file mode 100644 index 0000000..0477338 Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_512x512 1.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_512x512 1.png new file mode 100644 index 0000000..f64fcd6 Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_512x512 1.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x 1.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x 1.png new file mode 100644 index 0000000..d5e9e4c Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x 1.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png new file mode 100644 index 0000000..73472cb Binary files /dev/null and b/YggdrasilSwiftUI/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png differ diff --git a/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/Contents.json b/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/Contents.json new file mode 100644 index 0000000..0d0b31a --- /dev/null +++ b/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/Contents.json @@ -0,0 +1,27 @@ +{ + "images" : [ + { + "filename" : "ygg-neilalexander.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "ygg-neilalexander 1.svg", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "ygg-neilalexander 2.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/ygg-neilalexander 1.svg b/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/ygg-neilalexander 1.svg new file mode 100644 index 0000000..d222200 --- /dev/null +++ b/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/ygg-neilalexander 1.svg @@ -0,0 +1,157 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/ygg-neilalexander 2.svg b/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/ygg-neilalexander 2.svg new file mode 100644 index 0000000..d222200 --- /dev/null +++ b/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/ygg-neilalexander 2.svg @@ -0,0 +1,157 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/ygg-neilalexander.svg b/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/ygg-neilalexander.svg new file mode 100644 index 0000000..d222200 --- /dev/null +++ b/YggdrasilSwiftUI/Assets.xcassets/YggdrasilLogo.imageset/ygg-neilalexander.svg @@ -0,0 +1,157 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/YggdrasilSwiftUI/PeersView.swift b/YggdrasilSwiftUI/PeersView.swift index 4bddbc5..2a00a49 100644 --- a/YggdrasilSwiftUI/PeersView.swift +++ b/YggdrasilSwiftUI/PeersView.swift @@ -8,18 +8,32 @@ import SwiftUI struct PeersView: View { - @State private var peers = ["Paul", "Taylor", "Adele"] + // @Binding public var yggdrasilConfiguration: ConfigurationProxy + @ObservedObject private var appDelegate = Application.appDelegate - @State private var multicastAdvertise = false - @State private var multicastListen = false + @State private var peers = ["Paul", "Taylor", "Adele"] var body: some View { Form { Section(content: { - ForEach(peers, id: \.self) { peer in - Text(peer) + ForEach(Array(appDelegate.yggdrasilConfig.peers.enumerated()), id: \.offset) { index, peer in + HStack() { + Text(peer) + //TextField("", text: $yggdrasilConfiguration.peers[index]) + // .multilineTextAlignment(.leading) +#if os(macOS) + Spacer() + Button(role: .destructive) { + print("Deleting") + } label: { + Image(systemName: "xmark.circle.fill") + } + .buttonStyle(.plain) +#endif + } } .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) @@ -28,7 +42,7 @@ struct PeersView: View { }) Section(content: { - Toggle(isOn: $multicastAdvertise) { + Toggle(isOn: $appDelegate.yggdrasilConfig.multicastBeacons) { VStack(alignment: .leading) { Text("Discoverable over multicast") Text("Make your device discoverable to other Yggdrasil nodes on the same Wi-Fi network.") @@ -36,7 +50,7 @@ struct PeersView: View { .foregroundColor(.gray) } } - Toggle(isOn: $multicastListen) { + Toggle(isOn: $appDelegate.yggdrasilConfig.multicastListen) { VStack(alignment: .leading) { Text("Search for multicast peers") Text("Automatically connect to discoverable Yggdrasil nodes on the same Wi-Fi network.") diff --git a/YggdrasilSwiftUI/SettingsView.swift b/YggdrasilSwiftUI/SettingsView.swift index 61aaf90..d0dbe6d 100644 --- a/YggdrasilSwiftUI/SettingsView.swift +++ b/YggdrasilSwiftUI/SettingsView.swift @@ -8,10 +8,10 @@ import SwiftUI struct SettingsView: View { - @State private var deviceName = "" + //@Binding public var yggdrasilConfiguration: ConfigurationProxy + @ObservedObject private var appDelegate = Application.appDelegate - @State private var autoStartOnWiFi = false - @State private var autoStartOnCellular = false + @State private var deviceName = "" var body: some View { Form { @@ -22,8 +22,14 @@ struct SettingsView: View { }) Section(content: { - Toggle("Wi-Fi", isOn: $autoStartOnWiFi) - Toggle("Mobile Network", isOn: $autoStartOnCellular) + Toggle("Any network connection", isOn: $appDelegate.yggdrasilConfig.autoStartAny) + Toggle("Wi-Fi networks", isOn: $appDelegate.yggdrasilConfig.autoStartWiFi) +#if os(macOS) + Toggle("Ethernet networks", isOn: $appDelegate.yggdrasilConfig.autoStartEthernet) +#endif +#if os(iOS) + Toggle("Mobile data", isOn: $appDelegate.yggdrasilConfig.autoStartMobile) +#endif }, header: { Text("Automatically start when connected to") }) @@ -36,6 +42,7 @@ struct SettingsView: View { #if os(macOS) .buttonStyle(.link) #endif + .foregroundColor(.accentColor) Text("Import configuration from another device, including the public key and Yggdrasil IP address.") .font(.system(size: 11)) .foregroundColor(.gray) @@ -48,6 +55,7 @@ struct SettingsView: View { #if os(macOS) .buttonStyle(.link) #endif + .foregroundColor(.accentColor) 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) diff --git a/YggdrasilSwiftUI/StatusView.swift b/YggdrasilSwiftUI/StatusView.swift index 6cbad4f..ecacce3 100644 --- a/YggdrasilSwiftUI/StatusView.swift +++ b/YggdrasilSwiftUI/StatusView.swift @@ -14,8 +14,6 @@ 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 @@ -35,9 +33,9 @@ struct StatusView: View { if !appDelegate.yggdrasilEnabled { return "Not enabled" } else if !appDelegate.yggdrasilConnected { - return "Not connected" + return "No peers connected" } else { - return "Connected" + return "Connected to \(appDelegate.yggdrasilPeers.count) peer(s)" } } @@ -46,9 +44,6 @@ struct StatusView: View { Section(content: { VStack(alignment: .leading) { Toggle("Enable Yggdrasil", isOn: $appDelegate.yggdrasilEnabled) - .onTapGesture { - appDelegate.toggleYggdrasil() - } HStack { Image(systemName: "circlebadge.fill") .foregroundColor(statusBadgeColor) @@ -58,6 +53,12 @@ struct StatusView: View { .onChange(of: appDelegate.yggdrasilEnabled) { newValue in statusBadgeColor = getStatusBadgeColor() } + .onChange(of: appDelegate.yggdrasilConnected) { newValue in + statusBadgeColor = getStatusBadgeColor() + } + .onChange(of: appDelegate.yggdrasilPeers.count) { newValue in + statusBadgeColor = getStatusBadgeColor() + } Text(statusBadgeText) .foregroundColor(.gray) .font(.system(size: 11)) @@ -67,6 +68,12 @@ struct StatusView: View { .onChange(of: appDelegate.yggdrasilEnabled) { newValue in statusBadgeText = getStatusBadgeText() } + .onChange(of: appDelegate.yggdrasilConnected) { newValue in + statusBadgeText = getStatusBadgeText() + } + .onChange(of: appDelegate.yggdrasilPeers.count) { newValue in + statusBadgeText = getStatusBadgeText() + } } } HStack { @@ -83,29 +90,38 @@ struct StatusView: View { Spacer() Text(appDelegate.yggdrasilIP) .foregroundColor(Color.gray) + .truncationMode(.head) + .lineLimit(1) + .textSelection(.enabled) } HStack { Text("Subnet") Spacer() Text(appDelegate.yggdrasilSubnet) .foregroundColor(Color.gray) + .truncationMode(.head) + .lineLimit(1) + .textSelection(.enabled) } HStack { Text("Coordinates") Spacer() Text(appDelegate.yggdrasilCoords) .foregroundColor(Color.gray) + .truncationMode(.tail) + .lineLimit(1) + .textSelection(.enabled) } - /* HStack { Text("Public Key") Spacer() - Text("N/A") + Text(appDelegate.yggdrasilPublicKey) .foregroundColor(Color.gray) - .font(.system(size: 15, design: .monospaced)) + .font(.system(size: 13, design: .monospaced)) .truncationMode(.tail) + .lineLimit(1) + .textSelection(.enabled) } - */ }) } .formStyle(.grouped) @@ -118,8 +134,6 @@ struct StatusView: View { struct StatusView_Previews: PreviewProvider { static var previews: some View { - @State var config = ConfigurationProxy() - - StatusView(yggdrasilConfiguration: $config) + StatusView() } }