mirror of
				https://github.com/yggdrasil-network/yggdrasil-ios.git
				synced 2025-11-04 03:05:09 +03:00 
			
		
		
		
	Various tweaks
This commit is contained in:
		
							parent
							
								
									0245b6db5e
								
							
						
					
					
						commit
						9ce78d5007
					
				
					 9 changed files with 471 additions and 18 deletions
				
			
		
							
								
								
									
										252
									
								
								Yggdrasil Network Cross-Platform/ConfigurationProxy.swift
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								Yggdrasil Network Cross-Platform/ConfigurationProxy.swift
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,252 @@
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  ConfigurationProxy.swift
 | 
				
			||||||
 | 
					//  YggdrasilNetwork
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  Created by Neil Alexander on 07/01/2019.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if canImport(UIKit)
 | 
				
			||||||
 | 
					import UIKit
 | 
				
			||||||
 | 
					#elseif canImport(AppKit)
 | 
				
			||||||
 | 
					import AppKit
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					import Yggdrasil
 | 
				
			||||||
 | 
					import NetworkExtension
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if os(iOS)
 | 
				
			||||||
 | 
					class PlatformItemSource: NSObject, UIActivityItemSource {
 | 
				
			||||||
 | 
					    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
 | 
				
			||||||
 | 
					        return "yggdrasil.conf"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
 | 
				
			||||||
 | 
					        return nil
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#elseif os(OSX)
 | 
				
			||||||
 | 
					class PlatformItemSource: NSObject {}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigurationProxy: PlatformItemSource {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var json: Data? = nil
 | 
				
			||||||
 | 
					    private var dict: [String: Any]? = nil
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    override init() {
 | 
				
			||||||
 | 
					        super.init()
 | 
				
			||||||
 | 
					        self.json = MobileGenerateConfigJSON()
 | 
				
			||||||
 | 
					        do {
 | 
				
			||||||
 | 
					            try self.convertToDict()
 | 
				
			||||||
 | 
					        } catch {
 | 
				
			||||||
 | 
					            NSLog("ConfigurationProxy: Error deserialising JSON (\(error))")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        #if os(iOS)
 | 
				
			||||||
 | 
					        self.set("name", inSection: "NodeInfo", to: UIDevice.current.name)
 | 
				
			||||||
 | 
					        #elseif os(OSX)
 | 
				
			||||||
 | 
					        self.set("name", inSection: "NodeInfo", to: Host.current().localizedName ?? "")
 | 
				
			||||||
 | 
					        #endif
 | 
				
			||||||
 | 
					        self.fix()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    init(json: Data) throws {
 | 
				
			||||||
 | 
					        super.init()
 | 
				
			||||||
 | 
					        self.json = json
 | 
				
			||||||
 | 
					        try self.convertToDict()
 | 
				
			||||||
 | 
					        self.fix()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private func fix() {
 | 
				
			||||||
 | 
					        self.set("Listen", to: [] as [String])
 | 
				
			||||||
 | 
					        self.set("AdminListen", to: "none")
 | 
				
			||||||
 | 
					        self.set("IfName", to: "dummy")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if self.get("AutoStart") == nil {
 | 
				
			||||||
 | 
					            self.set("AutoStart", to: ["WiFi": false, "Mobile": false] as [String: Bool])
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        let multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
 | 
				
			||||||
 | 
					        if multicastInterfaces.count == 0 {
 | 
				
			||||||
 | 
					            self.set("MulticastInterfaces", to: [
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    "Regex": "en.*",
 | 
				
			||||||
 | 
					                    "Beacon": true,
 | 
				
			||||||
 | 
					                    "Listen": true,
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            ])
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public var multicastBeacons: Bool {
 | 
				
			||||||
 | 
					        get {
 | 
				
			||||||
 | 
					            let multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
 | 
				
			||||||
 | 
					            if multicastInterfaces.count == 0 {
 | 
				
			||||||
 | 
					                return false
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return multicastInterfaces[0]["Beacon"] as? Bool ?? true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        set {
 | 
				
			||||||
 | 
					            var multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
 | 
				
			||||||
 | 
					            multicastInterfaces[0]["Beacon"] = newValue
 | 
				
			||||||
 | 
					            self.set("MulticastInterfaces", to: multicastInterfaces)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public var multicastListen: Bool {
 | 
				
			||||||
 | 
					        get {
 | 
				
			||||||
 | 
					            let multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
 | 
				
			||||||
 | 
					            if multicastInterfaces.count == 0 {
 | 
				
			||||||
 | 
					                return false
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return multicastInterfaces[0]["Listen"] as? Bool ?? true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        set {
 | 
				
			||||||
 | 
					            var multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
 | 
				
			||||||
 | 
					            multicastInterfaces[0]["Listen"] = newValue
 | 
				
			||||||
 | 
					            self.set("MulticastInterfaces", to: multicastInterfaces)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func get(_ key: String) -> Any? {
 | 
				
			||||||
 | 
					        if let dict = self.dict {
 | 
				
			||||||
 | 
					            if dict.keys.contains(key) {
 | 
				
			||||||
 | 
					                return dict[key]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return nil
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return nil
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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] ?? []
 | 
				
			||||||
 | 
					                temp.append(value)
 | 
				
			||||||
 | 
					                self.dict!.updateValue(temp, forKey: key)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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] ?? []
 | 
				
			||||||
 | 
					                if let index = temp.firstIndex(of: value) {
 | 
				
			||||||
 | 
					                    temp.remove(at: index)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                self.dict!.updateValue(temp, forKey: key)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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] ?? []
 | 
				
			||||||
 | 
					                temp.remove(at: index)
 | 
				
			||||||
 | 
					                self.dict!.updateValue(temp, forKey: key)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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?) {
 | 
				
			||||||
 | 
					        if self.dict != nil {
 | 
				
			||||||
 | 
					            if self.dict!.keys.contains(section), let value = value {
 | 
				
			||||||
 | 
					                var temp = self.dict![section] as? [String: Any] ?? [:]
 | 
				
			||||||
 | 
					                temp.updateValue(value, forKey: key)
 | 
				
			||||||
 | 
					                self.dict!.updateValue(temp, forKey: section)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func data() -> Data? {
 | 
				
			||||||
 | 
					        do {
 | 
				
			||||||
 | 
					            try self.convertToJson()
 | 
				
			||||||
 | 
					            return self.json
 | 
				
			||||||
 | 
					        } catch {
 | 
				
			||||||
 | 
					            return nil
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func save(to manager: inout NETunnelProviderManager) throws {
 | 
				
			||||||
 | 
					        self.fix()
 | 
				
			||||||
 | 
					        if let data = self.data() {
 | 
				
			||||||
 | 
					            let providerProtocol = NETunnelProviderProtocol()
 | 
				
			||||||
 | 
					            #if os(iOS)
 | 
				
			||||||
 | 
					            providerProtocol.providerBundleIdentifier = "eu.neilalexander.yggdrasil.extension"
 | 
				
			||||||
 | 
					            #elseif os(OSX)
 | 
				
			||||||
 | 
					            providerProtocol.providerBundleIdentifier = "eu.neilalexander.yggdrasilmac.extension"
 | 
				
			||||||
 | 
					            #endif
 | 
				
			||||||
 | 
					            providerProtocol.providerConfiguration = [ "json": data ]
 | 
				
			||||||
 | 
					            providerProtocol.serverAddress = "yggdrasil"
 | 
				
			||||||
 | 
					            providerProtocol.username = self.get("PublicKey") as? String ?? self.get("SigningPublicKey") as? String ?? "(unknown public key)"
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            let disconnectrule = NEOnDemandRuleDisconnect()
 | 
				
			||||||
 | 
					            var rules: [NEOnDemandRule] = [disconnectrule]
 | 
				
			||||||
 | 
					            if self.get("WiFi", inSection: "AutoStart") as? Bool ?? false {
 | 
				
			||||||
 | 
					                let wifirule = NEOnDemandRuleConnect()
 | 
				
			||||||
 | 
					                wifirule.interfaceTypeMatch = .wiFi
 | 
				
			||||||
 | 
					                rules.insert(wifirule, at: 0)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #if canImport(UIKit)
 | 
				
			||||||
 | 
					            if self.get("Mobile", inSection: "AutoStart") as? Bool ?? false {
 | 
				
			||||||
 | 
					                let mobilerule = NEOnDemandRuleConnect()
 | 
				
			||||||
 | 
					                mobilerule.interfaceTypeMatch = .cellular
 | 
				
			||||||
 | 
					                rules.insert(mobilerule, at: 0)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #endif
 | 
				
			||||||
 | 
					            manager.onDemandRules = rules
 | 
				
			||||||
 | 
					            manager.isOnDemandEnabled = rules.count > 1
 | 
				
			||||||
 | 
					            providerProtocol.disconnectOnSleep = rules.count > 1
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            manager.protocolConfiguration = providerProtocol
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            manager.saveToPreferences(completionHandler: { (error:Error?) in
 | 
				
			||||||
 | 
					                if let error = error {
 | 
				
			||||||
 | 
					                    print(error)
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    print("Save successfully")
 | 
				
			||||||
 | 
					                    NotificationCenter.default.post(name: NSNotification.Name.YggdrasilSettingsUpdated, object: self)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private func convertToDict() throws {
 | 
				
			||||||
 | 
					        self.dict = try JSONSerialization.jsonObject(with: self.json!, options: []) as? [String: Any]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private func convertToJson() throws {
 | 
				
			||||||
 | 
					        self.json = try JSONSerialization.data(withJSONObject: self.dict as Any, options: .prettyPrinted)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #if canImport(UIKit)
 | 
				
			||||||
 | 
					    override func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
 | 
				
			||||||
 | 
					        return "yggdrasil.conf"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    override func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
 | 
				
			||||||
 | 
					        return self.data()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
 | 
				
			||||||
 | 
					        if let pubkey = self.get("PublicKey") as? String {
 | 
				
			||||||
 | 
					            return "yggdrasil-\(pubkey).conf.json"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "yggdrasil.conf.json"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										158
									
								
								Yggdrasil Network Cross-Platform/CrossPlatformAppDelegate.swift
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								Yggdrasil Network Cross-Platform/CrossPlatformAppDelegate.swift
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,158 @@
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  AppDelegateExtension.swift
 | 
				
			||||||
 | 
					//  Yggdrasil Network
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  Created by Neil Alexander on 11/01/2019.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					import NetworkExtension
 | 
				
			||||||
 | 
					import Yggdrasil
 | 
				
			||||||
 | 
					import UIKit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CrossPlatformAppDelegate: PlatformAppDelegate {
 | 
				
			||||||
 | 
					    var vpnManager: NETunnelProviderManager = NETunnelProviderManager()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #if os(iOS)
 | 
				
			||||||
 | 
					    let yggdrasilComponent = "eu.neilalexander.yggdrasil.extension"
 | 
				
			||||||
 | 
					    #elseif os(OSX)
 | 
				
			||||||
 | 
					    let yggdrasilComponent = "eu.neilalexander.yggdrasilmac.extension"
 | 
				
			||||||
 | 
					    #endif
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    var yggdrasilConfig: ConfigurationProxy? = nil
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    var yggdrasilAdminTimer: DispatchSourceTimer?
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    var yggdrasilSelfIP: String = "N/A"
 | 
				
			||||||
 | 
					    var yggdrasilSelfSubnet: String = "N/A"
 | 
				
			||||||
 | 
					    var yggdrasilSelfCoords: String = "[]"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var yggdrasilPeers: [[String: Any]] = [[:]]
 | 
				
			||||||
 | 
					    var yggdrasilDHT: [[String: Any]] = [[:]]
 | 
				
			||||||
 | 
					    var yggdrasilNodeInfo: [String: Any] = [:]
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func applicationDidBecomeActive(_ application: UIApplication) {
 | 
				
			||||||
 | 
					        if self.yggdrasilAdminTimer == nil {
 | 
				
			||||||
 | 
					            self.yggdrasilAdminTimer = DispatchSource.makeTimerSource(flags: .strict, queue: DispatchQueue(label: "Admin Queue"))
 | 
				
			||||||
 | 
					            self.yggdrasilAdminTimer!.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.seconds(2), leeway: DispatchTimeInterval.seconds(1))
 | 
				
			||||||
 | 
					            self.yggdrasilAdminTimer!.setEventHandler {
 | 
				
			||||||
 | 
					                self.makeIPCRequests()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if self.yggdrasilAdminTimer != nil {
 | 
				
			||||||
 | 
					            self.yggdrasilAdminTimer!.resume()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        NotificationCenter.default.addObserver(forName: .NEVPNStatusDidChange, object: nil, queue: nil, using: { notification in
 | 
				
			||||||
 | 
					            if let conn = notification.object as? NEVPNConnection {
 | 
				
			||||||
 | 
					                self.updateStatus(conn: conn)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        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()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func applicationWillResignActive(_ application: UIApplication) {
 | 
				
			||||||
 | 
					        if self.yggdrasilAdminTimer != nil {
 | 
				
			||||||
 | 
					            self.yggdrasilAdminTimer!.suspend()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func vpnTunnelProviderManagerInit() {
 | 
				
			||||||
 | 
					        NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in
 | 
				
			||||||
 | 
					            if let error = error {
 | 
				
			||||||
 | 
					                print(error)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if let savedManagers = savedManagers {
 | 
				
			||||||
 | 
					                for manager in savedManagers {
 | 
				
			||||||
 | 
					                    if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.yggdrasilComponent {
 | 
				
			||||||
 | 
					                        print("Found saved VPN Manager")
 | 
				
			||||||
 | 
					                        self.vpnManager = manager
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            self.vpnManager.loadFromPreferences(completionHandler: { (error: Error?) in
 | 
				
			||||||
 | 
					                if let error = error {
 | 
				
			||||||
 | 
					                    print(error)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                if let vpnConfig = self.vpnManager.protocolConfiguration as? NETunnelProviderProtocol,
 | 
				
			||||||
 | 
					                    let confJson = vpnConfig.providerConfiguration!["json"] as? Data {
 | 
				
			||||||
 | 
					                    print("Found existing protocol configuration")
 | 
				
			||||||
 | 
					                    self.yggdrasilConfig = try? ConfigurationProxy(json: confJson)
 | 
				
			||||||
 | 
					                } else  {
 | 
				
			||||||
 | 
					                    print("Generating new protocol configuration")
 | 
				
			||||||
 | 
					                    self.yggdrasilConfig = ConfigurationProxy()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                self.vpnManager.localizedDescription = "Yggdrasil"
 | 
				
			||||||
 | 
					                self.vpnManager.isEnabled = true
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                if let config = self.yggdrasilConfig {
 | 
				
			||||||
 | 
					                    try? config.save(to: &self.vpnManager)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func makeIPCRequests() {
 | 
				
			||||||
 | 
					        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.yggdrasilSelfIP = String(data: address, encoding: .utf8)!
 | 
				
			||||||
 | 
					                    NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            try? session.sendProviderMessage("subnet".data(using: .utf8)!) { (subnet) in
 | 
				
			||||||
 | 
					                if let subnet = subnet {
 | 
				
			||||||
 | 
					                    self.yggdrasilSelfSubnet = String(data: subnet, encoding: .utf8)!
 | 
				
			||||||
 | 
					                    NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            try? session.sendProviderMessage("coords".data(using: .utf8)!) { (coords) in
 | 
				
			||||||
 | 
					                if let coords = coords {
 | 
				
			||||||
 | 
					                    self.yggdrasilSelfCoords = String(data: coords, encoding: .utf8)!
 | 
				
			||||||
 | 
					                    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]] {
 | 
				
			||||||
 | 
					                        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]] {
 | 
				
			||||||
 | 
					                        self.yggdrasilDHT = jsonResponse
 | 
				
			||||||
 | 
					                        NotificationCenter.default.post(name: .YggdrasilDHTUpdated, object: nil)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    func clearStatus() {
 | 
				
			||||||
 | 
					        self.yggdrasilSelfIP = "N/A"
 | 
				
			||||||
 | 
					        self.yggdrasilSelfSubnet = "N/A"
 | 
				
			||||||
 | 
					        self.yggdrasilSelfCoords = "[]"
 | 
				
			||||||
 | 
					        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)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -9,24 +9,28 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private var readThread: Thread?
 | 
					    private var readThread: Thread?
 | 
				
			||||||
    private var writeThread: Thread?
 | 
					    private var writeThread: Thread?
 | 
				
			||||||
    private var writeBuffer = Data(count: 65535)
 | 
					    private let readBuffer = NSMutableData(length: 65535)
 | 
				
			||||||
 | 
					    private let writeBuffer = Data(count: 65535)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    @objc func readPacketsFromTun() {
 | 
					    @objc func readPacketsFromTun() {
 | 
				
			||||||
        autoreleasepool {
 | 
					        self.packetFlow.readPackets { (packets: [Data], protocols: [NSNumber]) in
 | 
				
			||||||
            self.packetFlow.readPackets { (packets: [Data], protocols: [NSNumber]) in
 | 
					            autoreleasepool {
 | 
				
			||||||
                for packet in packets {
 | 
					                for packet in packets {
 | 
				
			||||||
                    try? self.yggdrasil.sendBuffer(packet, length: packet.count)
 | 
					                    try? self.yggdrasil.sendBuffer(packet, length: packet.count)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                self.readPacketsFromTun()
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            self.readPacketsFromTun()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @objc func writePacketsToTun() {
 | 
					    @objc func writePacketsToTun() {
 | 
				
			||||||
 | 
					        var n: Int = 0
 | 
				
			||||||
 | 
					        let readData = Data(bytesNoCopy: readBuffer!.mutableBytes, count: 65535, deallocator: .none)
 | 
				
			||||||
        while true {
 | 
					        while true {
 | 
				
			||||||
            autoreleasepool {
 | 
					            autoreleasepool {
 | 
				
			||||||
                if let data = try? self.yggdrasil.recv() {
 | 
					                try? self.yggdrasil.recvBuffer(readBuffer as Data?, ret0_: &n)
 | 
				
			||||||
                    self.packetFlow.writePackets([data], withProtocols: [NSNumber](repeating: AF_INET6 as NSNumber, count: 1))
 | 
					                if n > 0 {
 | 
				
			||||||
 | 
					                  self.packetFlow.writePackets([readData[..<n]], withProtocols: [NSNumber](repeating: AF_INET6 as NSNumber, count: 1))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,5 +15,5 @@ extension Notification.Name {
 | 
				
			||||||
    static let YggdrasilSelfUpdated = Notification.Name("YggdrasilSelfUpdated")
 | 
					    static let YggdrasilSelfUpdated = Notification.Name("YggdrasilSelfUpdated")
 | 
				
			||||||
    static let YggdrasilPeersUpdated = Notification.Name("YggdrasilPeersUpdated")
 | 
					    static let YggdrasilPeersUpdated = Notification.Name("YggdrasilPeersUpdated")
 | 
				
			||||||
    static let YggdrasilSettingsUpdated = Notification.Name("YggdrasilSettingsUpdated")
 | 
					    static let YggdrasilSettingsUpdated = Notification.Name("YggdrasilSettingsUpdated")
 | 
				
			||||||
    static let YggdrasilDHTUpdated = Notification.Name("YggdrasilPeersUpdated")
 | 
					    static let YggdrasilDHTUpdated = Notification.Name("YggdrasilDHTUpdated")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										20
									
								
								Yggdrasil Network iOS/Extensions/Data.swift
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Yggdrasil Network iOS/Extensions/Data.swift
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  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
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
| 
						 | 
					@ -38,17 +38,16 @@
 | 
				
			||||||
	</array>
 | 
						</array>
 | 
				
			||||||
	<key>UISupportedInterfaceOrientations</key>
 | 
						<key>UISupportedInterfaceOrientations</key>
 | 
				
			||||||
	<array>
 | 
						<array>
 | 
				
			||||||
		<string>UIInterfaceOrientationPortrait</string>
 | 
					 | 
				
			||||||
		<string>UIInterfaceOrientationLandscapeLeft</string>
 | 
							<string>UIInterfaceOrientationLandscapeLeft</string>
 | 
				
			||||||
		<string>UIInterfaceOrientationLandscapeRight</string>
 | 
							<string>UIInterfaceOrientationLandscapeRight</string>
 | 
				
			||||||
 | 
							<string>UIInterfaceOrientationPortrait</string>
 | 
				
			||||||
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
 | 
							<string>UIInterfaceOrientationPortraitUpsideDown</string>
 | 
				
			||||||
	</array>
 | 
						</array>
 | 
				
			||||||
	<key>UISupportedInterfaceOrientations~ipad</key>
 | 
						<key>UISupportedInterfaceOrientations~ipad</key>
 | 
				
			||||||
	<array>
 | 
						<array>
 | 
				
			||||||
		<string>UIInterfaceOrientationPortrait</string>
 | 
					 | 
				
			||||||
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
 | 
					 | 
				
			||||||
		<string>UIInterfaceOrientationLandscapeLeft</string>
 | 
							<string>UIInterfaceOrientationLandscapeLeft</string>
 | 
				
			||||||
		<string>UIInterfaceOrientationLandscapeRight</string>
 | 
							<string>UIInterfaceOrientationLandscapeRight</string>
 | 
				
			||||||
 | 
							<string>UIInterfaceOrientationPortraitUpsideDown</string>
 | 
				
			||||||
	</array>
 | 
						</array>
 | 
				
			||||||
	<key>UTExportedTypeDeclarations</key>
 | 
						<key>UTExportedTypeDeclarations</key>
 | 
				
			||||||
	<array>
 | 
						<array>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,9 @@
 | 
				
			||||||
		3939196D21E39313009320F3 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3939196C21E39313009320F3 /* UIDevice.swift */; };
 | 
							3939196D21E39313009320F3 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3939196C21E39313009320F3 /* UIDevice.swift */; };
 | 
				
			||||||
		3939197321E39815009320F3 /* ToggleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3939197221E39815009320F3 /* ToggleTableViewCell.swift */; };
 | 
							3939197321E39815009320F3 /* ToggleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3939197221E39815009320F3 /* ToggleTableViewCell.swift */; };
 | 
				
			||||||
		394A1EB321DEA46400D9F553 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 394A1EB221DEA46400D9F553 /* SettingsViewController.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 */; };
 | 
							39682A392225AD15004FB670 /* CopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39682A382225AD15004FB670 /* CopyableLabel.swift */; };
 | 
				
			||||||
		3996AF38270328080070947D /* Yggdrasil.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3996AF37270328080070947D /* Yggdrasil.xcframework */; };
 | 
							3996AF38270328080070947D /* Yggdrasil.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3996AF37270328080070947D /* Yggdrasil.xcframework */; };
 | 
				
			||||||
		3996AF39270328080070947D /* Yggdrasil.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3996AF37270328080070947D /* Yggdrasil.xcframework */; };
 | 
							3996AF39270328080070947D /* Yggdrasil.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3996AF37270328080070947D /* Yggdrasil.xcframework */; };
 | 
				
			||||||
| 
						 | 
					@ -24,7 +27,7 @@
 | 
				
			||||||
		E593CE761DF8FC3C00D7265D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E593CE751DF8FC3C00D7265D /* Assets.xcassets */; };
 | 
							E593CE761DF8FC3C00D7265D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E593CE751DF8FC3C00D7265D /* Assets.xcassets */; };
 | 
				
			||||||
		E593CE791DF8FC3C00D7265D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E593CE771DF8FC3C00D7265D /* LaunchScreen.storyboard */; };
 | 
							E593CE791DF8FC3C00D7265D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E593CE771DF8FC3C00D7265D /* LaunchScreen.storyboard */; };
 | 
				
			||||||
		E593CE9C1DF905AF00D7265D /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E593CE9B1DF905AF00D7265D /* PacketTunnelProvider.swift */; };
 | 
							E593CE9C1DF905AF00D7265D /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E593CE9B1DF905AF00D7265D /* PacketTunnelProvider.swift */; };
 | 
				
			||||||
		E593CEA01DF905AF00D7265D /* YggdrasilNetworkExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = E593CE971DF905AF00D7265D /* YggdrasilNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
 | 
							E593CEA01DF905AF00D7265D /* YggdrasilNetworkExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E593CE971DF905AF00D7265D /* YggdrasilNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
 | 
				
			||||||
/* End PBXBuildFile section */
 | 
					/* End PBXBuildFile section */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Begin PBXContainerItemProxy section */
 | 
					/* Begin PBXContainerItemProxy section */
 | 
				
			||||||
| 
						 | 
					@ -38,15 +41,15 @@
 | 
				
			||||||
/* End PBXContainerItemProxy section */
 | 
					/* End PBXContainerItemProxy section */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Begin PBXCopyFilesBuildPhase section */
 | 
					/* Begin PBXCopyFilesBuildPhase section */
 | 
				
			||||||
		E593CEA41DF905B000D7265D /* Embed App Extensions */ = {
 | 
							E593CEA41DF905B000D7265D /* Embed Foundation Extensions */ = {
 | 
				
			||||||
			isa = PBXCopyFilesBuildPhase;
 | 
								isa = PBXCopyFilesBuildPhase;
 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
								buildActionMask = 2147483647;
 | 
				
			||||||
			dstPath = "";
 | 
								dstPath = "";
 | 
				
			||||||
			dstSubfolderSpec = 13;
 | 
								dstSubfolderSpec = 13;
 | 
				
			||||||
			files = (
 | 
								files = (
 | 
				
			||||||
				E593CEA01DF905AF00D7265D /* YggdrasilNetworkExtension.appex in Embed App Extensions */,
 | 
									E593CEA01DF905AF00D7265D /* YggdrasilNetworkExtension.appex in Embed Foundation Extensions */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			name = "Embed App Extensions";
 | 
								name = "Embed Foundation Extensions";
 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
								runOnlyForDeploymentPostprocessing = 0;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
/* End PBXCopyFilesBuildPhase section */
 | 
					/* End PBXCopyFilesBuildPhase section */
 | 
				
			||||||
| 
						 | 
					@ -59,6 +62,8 @@
 | 
				
			||||||
		3939196C21E39313009320F3 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = "<group>"; };
 | 
							3939196C21E39313009320F3 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		3939197221E39815009320F3 /* ToggleTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleTableViewCell.swift; sourceTree = "<group>"; };
 | 
							3939197221E39815009320F3 /* ToggleTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleTableViewCell.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		394A1EB221DEA46400D9F553 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
 | 
							394A1EB221DEA46400D9F553 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
 | 
				
			||||||
 | 
							3952ADB629945AF700B3835D /* ConfigurationProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurationProxy.swift; sourceTree = "<group>"; };
 | 
				
			||||||
 | 
							3952ADB929945AFA00B3835D /* CrossPlatformAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrossPlatformAppDelegate.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		39682A382225AD15004FB670 /* CopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyableLabel.swift; sourceTree = "<group>"; };
 | 
							39682A382225AD15004FB670 /* CopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyableLabel.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		3996AF37270328080070947D /* Yggdrasil.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Yggdrasil.xcframework; sourceTree = "<group>"; };
 | 
							3996AF37270328080070947D /* Yggdrasil.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Yggdrasil.xcframework; sourceTree = "<group>"; };
 | 
				
			||||||
		39AE88382319C93F0010FFF6 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
 | 
							39AE88382319C93F0010FFF6 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
 | 
				
			||||||
| 
						 | 
					@ -142,6 +147,16 @@
 | 
				
			||||||
			path = "UI Components";
 | 
								path = "UI Components";
 | 
				
			||||||
			sourceTree = "<group>";
 | 
								sourceTree = "<group>";
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
							3952ADB529945AE900B3835D /* Yggdrasil Network Core */ = {
 | 
				
			||||||
 | 
								isa = PBXGroup;
 | 
				
			||||||
 | 
								children = (
 | 
				
			||||||
 | 
									3952ADB929945AFA00B3835D /* CrossPlatformAppDelegate.swift */,
 | 
				
			||||||
 | 
									3952ADB629945AF700B3835D /* ConfigurationProxy.swift */,
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								name = "Yggdrasil Network Core";
 | 
				
			||||||
 | 
								path = "Yggdrasil Network Cross-Platform";
 | 
				
			||||||
 | 
								sourceTree = "<group>";
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
		399D032221DA775D0016354F /* Frameworks */ = {
 | 
							399D032221DA775D0016354F /* Frameworks */ = {
 | 
				
			||||||
			isa = PBXGroup;
 | 
								isa = PBXGroup;
 | 
				
			||||||
			children = (
 | 
								children = (
 | 
				
			||||||
| 
						 | 
					@ -154,6 +169,7 @@
 | 
				
			||||||
		E593CE621DF8FC3C00D7265D = {
 | 
							E593CE621DF8FC3C00D7265D = {
 | 
				
			||||||
			isa = PBXGroup;
 | 
								isa = PBXGroup;
 | 
				
			||||||
			children = (
 | 
								children = (
 | 
				
			||||||
 | 
									3952ADB529945AE900B3835D /* Yggdrasil Network Core */,
 | 
				
			||||||
				3913E99E21DB9B41001E0EC7 /* YggdrasilNetwork.entitlements */,
 | 
									3913E99E21DB9B41001E0EC7 /* YggdrasilNetwork.entitlements */,
 | 
				
			||||||
				3913E99C21DB9B1C001E0EC7 /* YggdrasilNetworkExtension.entitlements */,
 | 
									3913E99C21DB9B1C001E0EC7 /* YggdrasilNetworkExtension.entitlements */,
 | 
				
			||||||
				E593CE981DF905AF00D7265D /* Yggdrasil Network Extension */,
 | 
									E593CE981DF905AF00D7265D /* Yggdrasil Network Extension */,
 | 
				
			||||||
| 
						 | 
					@ -205,7 +221,7 @@
 | 
				
			||||||
				E593CE671DF8FC3C00D7265D /* Sources */,
 | 
									E593CE671DF8FC3C00D7265D /* Sources */,
 | 
				
			||||||
				E593CE681DF8FC3C00D7265D /* Frameworks */,
 | 
									E593CE681DF8FC3C00D7265D /* Frameworks */,
 | 
				
			||||||
				E593CE691DF8FC3C00D7265D /* Resources */,
 | 
									E593CE691DF8FC3C00D7265D /* Resources */,
 | 
				
			||||||
				E593CEA41DF905B000D7265D /* Embed App Extensions */,
 | 
									E593CEA41DF905B000D7265D /* Embed Foundation Extensions */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			buildRules = (
 | 
								buildRules = (
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
| 
						 | 
					@ -241,7 +257,7 @@
 | 
				
			||||||
			isa = PBXProject;
 | 
								isa = PBXProject;
 | 
				
			||||||
			attributes = {
 | 
								attributes = {
 | 
				
			||||||
				LastSwiftUpdateCheck = 1010;
 | 
									LastSwiftUpdateCheck = 1010;
 | 
				
			||||||
				LastUpgradeCheck = 1250;
 | 
									LastUpgradeCheck = 1420;
 | 
				
			||||||
				ORGANIZATIONNAME = "";
 | 
									ORGANIZATIONNAME = "";
 | 
				
			||||||
				TargetAttributes = {
 | 
									TargetAttributes = {
 | 
				
			||||||
					E593CE6A1DF8FC3C00D7265D = {
 | 
										E593CE6A1DF8FC3C00D7265D = {
 | 
				
			||||||
| 
						 | 
					@ -328,6 +344,8 @@
 | 
				
			||||||
				3939196D21E39313009320F3 /* UIDevice.swift in Sources */,
 | 
									3939196D21E39313009320F3 /* UIDevice.swift in Sources */,
 | 
				
			||||||
				394A1EB321DEA46400D9F553 /* SettingsViewController.swift in Sources */,
 | 
									394A1EB321DEA46400D9F553 /* SettingsViewController.swift in Sources */,
 | 
				
			||||||
				E593CE711DF8FC3C00D7265D /* TableViewController.swift in Sources */,
 | 
									E593CE711DF8FC3C00D7265D /* TableViewController.swift in Sources */,
 | 
				
			||||||
 | 
									3952ADBA29945AFA00B3835D /* CrossPlatformAppDelegate.swift in Sources */,
 | 
				
			||||||
 | 
									3952ADB729945AF700B3835D /* ConfigurationProxy.swift in Sources */,
 | 
				
			||||||
				39682A392225AD15004FB670 /* CopyableLabel.swift in Sources */,
 | 
									39682A392225AD15004FB670 /* CopyableLabel.swift in Sources */,
 | 
				
			||||||
				E593CE6F1DF8FC3C00D7265D /* AppDelegate.swift in Sources */,
 | 
									E593CE6F1DF8FC3C00D7265D /* AppDelegate.swift in Sources */,
 | 
				
			||||||
				3913E9C021DD3A51001E0EC7 /* SplitViewController.swift in Sources */,
 | 
									3913E9C021DD3A51001E0EC7 /* SplitViewController.swift in Sources */,
 | 
				
			||||||
| 
						 | 
					@ -341,6 +359,7 @@
 | 
				
			||||||
			files = (
 | 
								files = (
 | 
				
			||||||
				39CC924D221DEDD3004960DC /* NSNotification.swift in Sources */,
 | 
									39CC924D221DEDD3004960DC /* NSNotification.swift in Sources */,
 | 
				
			||||||
				E593CE9C1DF905AF00D7265D /* PacketTunnelProvider.swift in Sources */,
 | 
									E593CE9C1DF905AF00D7265D /* PacketTunnelProvider.swift in Sources */,
 | 
				
			||||||
 | 
									3952ADB829945AF700B3835D /* ConfigurationProxy.swift in Sources */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
								runOnlyForDeploymentPostprocessing = 0;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<Scheme
 | 
					<Scheme
 | 
				
			||||||
   LastUpgradeVersion = "1250"
 | 
					   LastUpgradeVersion = "1420"
 | 
				
			||||||
   version = "1.3">
 | 
					   version = "1.3">
 | 
				
			||||||
   <BuildAction
 | 
					   <BuildAction
 | 
				
			||||||
      parallelizeBuildables = "YES"
 | 
					      parallelizeBuildables = "YES"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<Scheme
 | 
					<Scheme
 | 
				
			||||||
   LastUpgradeVersion = "1250"
 | 
					   LastUpgradeVersion = "1420"
 | 
				
			||||||
   wasCreatedForAppExtension = "YES"
 | 
					   wasCreatedForAppExtension = "YES"
 | 
				
			||||||
   version = "2.0">
 | 
					   version = "2.0">
 | 
				
			||||||
   <BuildAction
 | 
					   <BuildAction
 | 
				
			||||||
| 
						 | 
					@ -84,6 +84,7 @@
 | 
				
			||||||
      savedToolIdentifier = ""
 | 
					      savedToolIdentifier = ""
 | 
				
			||||||
      useCustomWorkingDirectory = "NO"
 | 
					      useCustomWorkingDirectory = "NO"
 | 
				
			||||||
      debugDocumentVersioning = "YES"
 | 
					      debugDocumentVersioning = "YES"
 | 
				
			||||||
 | 
					      askForAppToLaunch = "Yes"
 | 
				
			||||||
      launchAutomaticallySubstyle = "2">
 | 
					      launchAutomaticallySubstyle = "2">
 | 
				
			||||||
      <BuildableProductRunnable
 | 
					      <BuildableProductRunnable
 | 
				
			||||||
         runnableDebuggingMode = "0">
 | 
					         runnableDebuggingMode = "0">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue