198 lines
6.7 KiB
Swift
198 lines
6.7 KiB
Swift
//
|
|
// IntercommSystem.swift
|
|
// io.privado.main.hive
|
|
//
|
|
// Created by Juraldinio on 6/21/20.
|
|
// Copyright © 2020 Privado. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
final class IntercommSystem {
|
|
|
|
enum Constants {
|
|
static let sudoPath = "/usr/bin/sudo"
|
|
static let ifconfigPath = "/sbin/ifconfig"
|
|
static let networksetupPath = "/usr/sbin/networksetup"
|
|
static let dscacheutilPath = "/usr/bin/dscacheutil"
|
|
}
|
|
|
|
private weak var client: HiveIntercommConsole?
|
|
|
|
init(client: HiveIntercommConsole?) {
|
|
self.client = client
|
|
}
|
|
|
|
// MARK: - Extractor methods
|
|
|
|
private func extractHardwarePorts(from stdout: String) -> [HardwarePort] {
|
|
|
|
guard let regExp = try? NSRegularExpression(pattern: #"(\([\d]+\)) ([\w]+)\n\(Hardware Port: ([\w]+), Device: ([\w]+)\)"#, options: []) else {
|
|
return []
|
|
}
|
|
|
|
return stdout
|
|
.components(separatedBy: "\n\n")
|
|
.map { String($0) }
|
|
.compactMap { value -> HardwarePort? in
|
|
guard let match = regExp.firstMatch(in: value, options: [], range: NSRange(location: 0, length: value.count))
|
|
, match.numberOfRanges > 4
|
|
, let port = value.substring(using: match.range(at: 3))
|
|
, let device = value.substring(using: match.range(at: 4)) else {
|
|
return nil
|
|
}
|
|
|
|
return HardwarePort(port: port, device: device)
|
|
}
|
|
.filter { $0.isValid }
|
|
}
|
|
|
|
private func extractIp(domain: String, from stdout: String) -> String? {
|
|
let results = stdout
|
|
.split(separator: "\n")
|
|
.map { String($0) }
|
|
|
|
guard results.contains(where: { $0.contains(domain) }) else { return nil }
|
|
|
|
guard let ipAddress = results.filter({ $0.contains("ip_address") }).first?.split(separator: " ")
|
|
, ipAddress.count > 1 else {
|
|
return nil
|
|
}
|
|
|
|
return String(ipAddress[1])
|
|
}
|
|
|
|
/*private func extractIFConfigSettings(from stdout: String) -> [InterfaceConfiguration] {
|
|
|
|
guard let regExp = try? NSRegularExpression(pattern: #"([\w\d]+): .+\n([ ]+inet ([\d\.]+) netmask .+\n|[ ]+inet6 [\w:]+.+\n|.+\n)+.+"#, options: []) else {
|
|
return []
|
|
}
|
|
|
|
return []
|
|
}*/
|
|
|
|
}
|
|
|
|
extension IntercommSystem: IntercommSystemType {
|
|
|
|
func updateRequired(short: String, bundle: String, completion: @escaping (Bool) -> Void) {
|
|
completion(false)
|
|
}
|
|
|
|
func version(completion: @escaping (String, String) -> Void) {
|
|
let shortVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0"
|
|
let bundleVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "1"
|
|
completion(shortVersion, bundleVersion)
|
|
}
|
|
|
|
func ping(completion: @escaping () -> Void) {
|
|
completion()
|
|
}
|
|
|
|
func ifconfig(completion: @escaping (String) -> Void) {
|
|
let result = main.run(Constants.ifconfigPath)
|
|
completion(result.stdout)
|
|
}
|
|
|
|
func hardwarePorts(completion: @escaping ([HardwarePort]) -> Void) {
|
|
let result = main.run(Constants.networksetupPath, ["-listnetworkserviceorder"])
|
|
self.client?.console(message: "hardwarePorts stdout: \(result.stdout)")
|
|
let ports = self.extractHardwarePorts(from: result.stdout)
|
|
completion(ports)
|
|
}
|
|
|
|
func flushDNS(completion: @escaping (Bool) -> Void) {
|
|
|
|
let arguments: [String]
|
|
|
|
let os = ProcessInfo().operatingSystemVersion
|
|
|
|
switch (os.majorVersion, os.minorVersion, os.patchVersion) {
|
|
case let (_, minor, _) where minor >= 12:
|
|
arguments = ["killall -HUP mDNSResponder",
|
|
"killall mDNSResponderHelper",
|
|
"dscacheutil -flushcache"]
|
|
case let (_, minor, _) where minor >= 11:
|
|
arguments = ["killall -HUP mDNSResponder"]
|
|
case let (_, 10, patch) where patch >= 4:
|
|
arguments = ["dscacheutil -flushcache",
|
|
"killall -HUP mDNSResponder"]
|
|
default:
|
|
arguments = []
|
|
}
|
|
|
|
guard !arguments.isEmpty else {
|
|
completion(false)
|
|
return
|
|
}
|
|
|
|
do {
|
|
try arguments.forEach {
|
|
let result = main.run(Constants.sudoPath, $0.split(separator: " ").map({ String($0) }))
|
|
guard result.succeeded else { throw NSError() }
|
|
//self.client?.console(message: "flushDNS stdout: \(result.stdout)")
|
|
if !result.stderror.isEmpty { self.client?.console(message: "flushDNS stderror: \(result.stderror)") }
|
|
}
|
|
} catch {
|
|
completion(false)
|
|
return
|
|
}
|
|
|
|
completion(true)
|
|
}
|
|
|
|
func resolveDNS(name: String, completion: @escaping (String) -> Void) {
|
|
let arguments = ["-q", "host", "-a", "name", name]
|
|
let result = main.run(Constants.dscacheutilPath, arguments)
|
|
let ipAddress = self.extractIp(domain: name, from: result.stdout) ?? ""
|
|
completion(ipAddress)
|
|
}
|
|
|
|
func changeDNS(servers: [String], hardware: String, completion: @escaping (Bool) -> Void) {
|
|
var arguments = ["-setdnsservers", hardware]
|
|
arguments.append(contentsOf: servers)
|
|
|
|
let result = main.run(Constants.networksetupPath, arguments)
|
|
completion(result.error == nil)
|
|
}
|
|
|
|
func currentDNS(hardware: [String], completion: @escaping ([String: [String]]) -> Void) {
|
|
|
|
let dns = hardware.reduce([String: [String]]()) { dns, hardware in
|
|
|
|
var dns = dns
|
|
let arguments = ["-getdnsservers", hardware]
|
|
|
|
let result = main.run(Constants.networksetupPath, arguments)
|
|
if result.error == nil {
|
|
if result.stdout.contains("aren't any DNS") {
|
|
dns[hardware] = []
|
|
} else {
|
|
dns[hardware] = result.stdout
|
|
.split(separator: "\n")
|
|
.map { String($0) }
|
|
}
|
|
}
|
|
|
|
return dns
|
|
}
|
|
|
|
completion(dns)
|
|
}
|
|
|
|
func removeUninstaller(completion: @escaping () -> Void) {
|
|
|
|
[
|
|
["launchctl", "unload", "/Library/LaunchDaemons/io.privado.main.uninstaller.plist"],
|
|
["rm", "/Library/LaunchDaemons/io.privado.main.uninstaller.plist"],
|
|
["rm", "/Library/PrivilegedHelperTools/io.privado.main.uninstaller"]
|
|
].forEach { arguments in
|
|
main.run(Constants.sudoPath, arguments)
|
|
}
|
|
|
|
completion()
|
|
|
|
}
|
|
|
|
}
|