Files
2020-12-23 21:26:29 +03:00

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()
}
}