Sanitised

This commit is contained in:
Neil Alexander 2020-07-19 14:20:15 +01:00
commit 52ca049b50
39 changed files with 3283 additions and 0 deletions

View file

@ -0,0 +1,220 @@
//
// 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.set("MulticastInterfaces", to: ["en*"] as [String])
self.set("AllowFromDirect", inSection: "SessionFirewall", to: true)
self.set("AllowFromRemote", inSection: "SessionFirewall", to: false)
self.set("AlwaysAllowOutbound", inSection: "SessionFirewall", to: true)
self.set("Enable", inSection: "SessionFirewall", to: true)
}
init(json: Data) throws {
super.init()
self.json = json
try self.convertToDict()
}
private func fix() {
self.set("Listen", to: [] as [String])
self.set("AdminListen", to: "none")
self.set("IfName", to: "dummy")
self.set("Enable", inSection: "SessionFirewall", to: true)
self.set("MaxTotalQueueSize", inSection: "SwitchOptions", to: 1048576)
if self.get("AutoStart") == nil {
self.set("AutoStart", to: ["WiFi": false, "Mobile": false] as [String: Bool])
}
let interfaces = self.get("MulticastInterfaces") as? [String] ?? []
if interfaces.contains(where: { $0 == "lo0" }) {
self.add("lo0", in: "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("EncryptionPublicKey") 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("EncryptionPublicKey") as? String, pubkey.count > 56 {
return "yggdrasil-\(pubkey.dropFirst(56)).conf.json"
}
return "yggdrasil.conf.json"
}
#endif
}

View file

@ -0,0 +1,151 @@
//
// 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 yggdrasilSwitchPeers: [[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
self.yggdrasilSelfIP = String(data: address!, encoding: .utf8)!
NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil)
}
try? session.sendProviderMessage("subnet".data(using: .utf8)!) { (subnet) in
self.yggdrasilSelfSubnet = String(data: subnet!, encoding: .utf8)!
NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil)
}
try? session.sendProviderMessage("coords".data(using: .utf8)!) { (coords) in
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 jsonResponse = try? JSONSerialization.jsonObject(with: peers!, options: []) as? [[String: Any]] {
self.yggdrasilPeers = jsonResponse
NotificationCenter.default.post(name: .YggdrasilPeersUpdated, object: nil)
}
}
try? session.sendProviderMessage("switchpeers".data(using: .utf8)!) { (switchpeers) in
if let jsonResponse = try? JSONSerialization.jsonObject(with: switchpeers!, options: []) as? [[String: Any]] {
self.yggdrasilSwitchPeers = jsonResponse
NotificationCenter.default.post(name: .YggdrasilSwitchPeersUpdated, object: nil)
}
}
}
}
func clearStatus() {
self.yggdrasilSelfIP = "N/A"
self.yggdrasilSelfSubnet = "N/A"
self.yggdrasilSelfCoords = "[]"
self.yggdrasilPeers = []
self.yggdrasilSwitchPeers = []
NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil)
NotificationCenter.default.post(name: .YggdrasilPeersUpdated, object: nil)
NotificationCenter.default.post(name: .YggdrasilSwitchPeersUpdated, object: nil)
}
}