Files

128 lines
4.5 KiB
Swift

//
// IntercommOpenVPN.swift
// io.privado.main.hive
//
// Created by Juraldinio on 6/21/20.
// Copyright © 2020 Privado. All rights reserved.
//
import Foundation
final class IntercommOpenVPN {
enum Constants {
static let sudoPath = "/usr/bin/sudo"
}
private var command: AsyncCommand?
private weak var client: HiveIntercommConsole?
init(client: HiveIntercommConsole?) {
self.client = client
}
private static func authenticate(path: String, username: String, password: String, client: Socket? = nil) {
do {
guard let client = client else {
let socket = try Socket.create(family: .unix, type: .stream, proto: .unix)
try socket.connect(to: path)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
Self.authenticate(path: path, username: username, password: password, client: socket)
}
return
}
if let data = try client.readString()
, data.split(separator: "\r\n").map({String($0)}).first(where: {$0.contains(">PASSWORD:Need")}) != nil {
try client.write(from: "username Auth \(username)\r\n")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
_ = try? client.write(from: "password Auth \(password)\r\n")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
client.close()
}
}
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
Self.authenticate(path: path, username: username, password: password, client: client)
}
}
} catch {
return
}
}
}
extension IntercommOpenVPN: IntercommOpenVPNType {
// swiftlint:disable function_parameter_count
func connect(type: Int, ovpnPath: String, configPath: String, username: String, password: String, completion: @escaping (Error?) -> Void) {
guard self.command == nil else {
let error = NSError(domain: PrivadoConstants.Hive.error,
code: PrivadoConstants.Hive.ErrorCode.ovpnAlreadyConnected,
userInfo: nil)
completion(error)
return
}
// Kill previously launched services
main.run(bash: "\(Constants.sudoPath) killall openvpn")
let socketPath = "/tmp/ovpn_privado_\(Int.random(in: 42..<255))"
let arguments = [ovpnPath,
"--config", configPath,
"--management", socketPath, "unix",
"--management-query-passwords",
"--mute-replay-warnings"]
let command = main.runAsync(Constants.sudoPath, arguments).onCompletion { [weak self] handler in
// Clean command link for indicate that we already finished process
self?.command = nil
print(handler)
}
command.stdout.onStringOutput { [weak self] output in
guard let client = self?.client else { return }
if output.contains("Need password(s) from management interface, waiting") {
Self.authenticate(path: socketPath, username: username, password: password)
return
}
client.console(message: "\(PrivadoConstants.Hive.preffixConsole)\(output)")
}
command.stderror.onStringOutput { [weak self] output in
guard let client = self?.client else { return }
client.console(message: "\(PrivadoConstants.Hive.preffixError)\(output)")
}
self.command = command
completion(nil)
}
// swiftlint:enable function_parameter_count
func disconnect(completion: @escaping (Error?) -> Void) {// sudo killall openvpn
guard let command = self.command else {
let error = NSError(domain: PrivadoConstants.Hive.error,
code: PrivadoConstants.Hive.ErrorCode.ovpnAlreadydisconnected,
userInfo: nil)
completion(error)
return
}
command.interrupt()
self.command = nil
completion(nil)
}
func isConnected(completion: @escaping (Bool) -> Void) {
completion(self.command != nil)
}
}