mirror of
https://github.com/yggdrasil-network/yggdrasil-ios.git
synced 2025-04-28 14:15:09 +03:00
App updates
This commit is contained in:
parent
2cb5eebcd2
commit
5fbb735f56
9 changed files with 204 additions and 91 deletions
|
@ -13,6 +13,8 @@ import AppKit
|
|||
import SwiftUI
|
||||
import Yggdrasil
|
||||
import NetworkExtension
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
#if os(iOS)
|
||||
class PlatformItemSource: NSObject, UIActivityItemSource {
|
||||
|
@ -31,9 +33,10 @@ class PlatformItemSource: NSObject {}
|
|||
class ConfigurationProxy: PlatformItemSource {
|
||||
private var manager: NETunnelProviderManager?
|
||||
private var json: Data? = nil
|
||||
private var dict: [String: Any]? = nil
|
||||
private var dict: [String: Any]? = [:]
|
||||
private var timer: Timer?
|
||||
|
||||
init(manager: NETunnelProviderManager? = nil) {
|
||||
init(manager: NETunnelProviderManager) {
|
||||
self.manager = manager
|
||||
super.init()
|
||||
|
||||
|
@ -64,14 +67,13 @@ 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: ["Any": false, "WiFi": false, "Mobile": false, "Ethernet": false] as [String: Bool])
|
||||
}
|
||||
|
||||
let multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
|
||||
if multicastInterfaces.count == 0 {
|
||||
if multicastInterfaces.count != 1 {
|
||||
self.set("MulticastInterfaces", to: [
|
||||
[
|
||||
"Regex": "en.*",
|
||||
|
@ -94,7 +96,7 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
var multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
|
||||
multicastInterfaces[0]["Beacon"] = newValue
|
||||
self.set("MulticastInterfaces", to: multicastInterfaces)
|
||||
self.trySave()
|
||||
self.saveSoon()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,7 +112,23 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
var multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
|
||||
multicastInterfaces[0]["Listen"] = newValue
|
||||
self.set("MulticastInterfaces", to: multicastInterfaces)
|
||||
self.trySave()
|
||||
self.saveSoon()
|
||||
}
|
||||
}
|
||||
|
||||
public var multicastPassword: String {
|
||||
get {
|
||||
let multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
|
||||
if multicastInterfaces.count == 0 {
|
||||
return ""
|
||||
}
|
||||
return multicastInterfaces[0]["Password"] as? String ?? ""
|
||||
}
|
||||
set {
|
||||
var multicastInterfaces = self.get("MulticastInterfaces") as? [[String: Any]] ?? []
|
||||
multicastInterfaces[0]["Password"] = newValue
|
||||
self.set("MulticastInterfaces", to: multicastInterfaces)
|
||||
self.saveSoon()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,7 +138,7 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
}
|
||||
set {
|
||||
self.set("Any", inSection: "AutoStart", to: newValue)
|
||||
self.trySave()
|
||||
self.saveSoon()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +148,7 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
}
|
||||
set {
|
||||
self.set("WiFi", inSection: "AutoStart", to: newValue)
|
||||
self.trySave()
|
||||
self.saveSoon()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,7 +158,7 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
}
|
||||
set {
|
||||
self.set("Ethernet", inSection: "AutoStart", to: newValue)
|
||||
self.trySave()
|
||||
self.saveSoon()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +168,17 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
}
|
||||
set {
|
||||
self.set("Mobile", inSection: "AutoStart", to: newValue)
|
||||
self.trySave()
|
||||
self.saveSoon()
|
||||
}
|
||||
}
|
||||
|
||||
public var deviceName: String {
|
||||
get {
|
||||
return self.get("name", inSection: "NodeInfo") as? String ?? ""
|
||||
}
|
||||
set {
|
||||
self.set("name", inSection: "NodeInfo", to: newValue)
|
||||
self.saveSoon()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +188,7 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
}
|
||||
set {
|
||||
self.set("Peers", to: newValue)
|
||||
self.trySave()
|
||||
self.saveSoon()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,10 +267,22 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
}
|
||||
}
|
||||
|
||||
private func trySave() {
|
||||
private func saveSoon() {
|
||||
self.timer?.invalidate()
|
||||
self.timer = Timer.scheduledTimer(
|
||||
timeInterval: 1.0,
|
||||
target: self,
|
||||
selector: #selector(saveFromTimer),
|
||||
userInfo: nil,
|
||||
repeats: false
|
||||
)
|
||||
}
|
||||
|
||||
@objc private func saveFromTimer() {
|
||||
if var manager = self.manager {
|
||||
try? self.save(to: &manager)
|
||||
}
|
||||
self.timer = nil
|
||||
}
|
||||
|
||||
func save(to manager: inout NETunnelProviderManager) throws {
|
||||
|
@ -254,6 +294,8 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
providerProtocol.serverAddress = "yggdrasil"
|
||||
providerProtocol.username = self.get("PublicKey") as? String ?? self.get("SigningPublicKey") as? String ?? "(unknown public key)"
|
||||
|
||||
NSLog(String(data: data, encoding: .utf8) ?? "(unknown)")
|
||||
|
||||
let disconnectrule = NEOnDemandRuleDisconnect()
|
||||
var rules: [NEOnDemandRule] = [disconnectrule]
|
||||
if self.get("Any", inSection: "AutoStart") as? Bool ?? false {
|
||||
|
@ -283,10 +325,10 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
manager.onDemandRules = rules
|
||||
manager.isOnDemandEnabled = rules.count > 1
|
||||
providerProtocol.disconnectOnSleep = rules.count > 1
|
||||
|
||||
|
||||
manager.protocolConfiguration = providerProtocol
|
||||
|
||||
manager.saveToPreferences(completionHandler: { (error:Error?) in
|
||||
manager.saveToPreferences(completionHandler: { error in
|
||||
if let error = error {
|
||||
print(error)
|
||||
} else {
|
||||
|
|
|
@ -22,11 +22,12 @@ typealias ApplicationDelegateAdaptor = NSApplicationDelegateAdaptor
|
|||
|
||||
class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject {
|
||||
var vpnManager: NETunnelProviderManager = NETunnelProviderManager()
|
||||
var yggdrasilConfig: ConfigurationProxy = ConfigurationProxy()
|
||||
var yggdrasilConfig: ConfigurationProxy
|
||||
let yggdrasilComponent = "eu.neilalexander.yggdrasil.extension"
|
||||
private var adminTimer: DispatchSourceTimer?
|
||||
|
||||
override init() {
|
||||
self.yggdrasilConfig = ConfigurationProxy(manager: self.vpnManager)
|
||||
super.init()
|
||||
|
||||
NotificationCenter.default.addObserver(forName: .NEVPNStatusDidChange, object: nil, queue: nil, using: { notification in
|
||||
|
@ -34,7 +35,6 @@ class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject {
|
|||
switch conn.status {
|
||||
case .connected:
|
||||
self.requestSummaryIPC()
|
||||
self.requestStatusIPC()
|
||||
case .disconnecting, .disconnected:
|
||||
self.clearStatus()
|
||||
default:
|
||||
|
@ -73,9 +73,7 @@ class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject {
|
|||
@Published var yggdrasilSubnet: String = "N/A"
|
||||
@Published var yggdrasilCoords: String = "[]"
|
||||
|
||||
@Published var yggdrasilPeers: [[String: Any]] = [[:]]
|
||||
@Published var yggdrasilDHT: [[String: Any]] = [[:]]
|
||||
@Published var yggdrasilNodeInfo: [String: Any] = [:]
|
||||
@Published var yggdrasilPeers: [YggdrasilPeer] = []
|
||||
|
||||
func yggdrasilVersion() -> String {
|
||||
return Yggdrasil.MobileGetVersion()
|
||||
|
@ -111,7 +109,7 @@ class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject {
|
|||
|
||||
func updateStatus(conn: NEVPNConnection) {
|
||||
if conn.status == .connected {
|
||||
self.requestStatusIPC()
|
||||
self.requestSummaryIPC()
|
||||
} else if conn.status == .disconnecting || conn.status == .disconnected {
|
||||
self.clearStatus()
|
||||
}
|
||||
|
@ -183,30 +181,14 @@ class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject {
|
|||
if let session = self.vpnManager.connection as? NETunnelProviderSession {
|
||||
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.yggdrasilEnabled = summary.enabled
|
||||
self.yggdrasilIP = summary.address
|
||||
self.yggdrasilSubnet = summary.subnet
|
||||
self.yggdrasilPublicKey = summary.publicKey
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
if let jsonResponse = try? JSONSerialization.jsonObject(with: status.dht, options: []) as? [[String: Any]] {
|
||||
self.yggdrasilDHT = jsonResponse
|
||||
}
|
||||
self.yggdrasilConnected = self.yggdrasilEnabled && self.yggdrasilPeers.count > 0 && self.yggdrasilDHT.count > 0
|
||||
self.yggdrasilPeers = summary.peers
|
||||
self.yggdrasilConnected = summary.peers.count > 0
|
||||
|
||||
print(self.yggdrasilPeers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -218,6 +200,5 @@ class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject {
|
|||
self.yggdrasilSubnet = "N/A"
|
||||
self.yggdrasilCoords = "[]"
|
||||
self.yggdrasilPeers = []
|
||||
self.yggdrasilDHT = []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,29 @@ struct YggdrasilSummary: Codable {
|
|||
var address: String
|
||||
var subnet: String
|
||||
var publicKey: String
|
||||
var enabled: Bool
|
||||
var peers: [YggdrasilPeer]
|
||||
|
||||
func list() -> [String] {
|
||||
return peers.map { $0.remote }
|
||||
}
|
||||
}
|
||||
|
||||
struct YggdrasilStatus: Codable {
|
||||
var enabled: Bool
|
||||
var coords: String
|
||||
var peers: Data
|
||||
var dht: Data
|
||||
struct YggdrasilPeer: Codable, Identifiable {
|
||||
var id: String { remote } // For Identifiable protocol
|
||||
let remote: String
|
||||
let up: Bool
|
||||
let address: String
|
||||
let key: String
|
||||
let priority: UInt8
|
||||
let cost: UInt16?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case remote = "URI"
|
||||
case up = "Up"
|
||||
case address = "IP"
|
||||
case key = "Key"
|
||||
case priority = "Priority"
|
||||
case cost = "Cost"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue