diff --git a/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift b/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift index 12899bb..bd3cefb 100644 --- a/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift +++ b/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift @@ -7,6 +7,7 @@ extension SSHAgent { /// The type of the SSH Agent Request, as described in https://tools.ietf.org/id/draft-miller-ssh-agent-01.html#rfc.section.5.1 public enum RequestType: UInt8, CustomDebugStringConvertible { + case requestIdentities = 11 case signRequest = 13 @@ -22,6 +23,7 @@ extension SSHAgent { /// The type of the SSH Agent Response, as described in https://tools.ietf.org/id/draft-miller-ssh-agent-01.html#rfc.section.5.1 public enum ResponseType: UInt8, CustomDebugStringConvertible { + case agentFailure = 5 case agentIdentitiesAnswer = 12 case agentSignResponse = 14 diff --git a/Sources/Packages/Sources/SecretAgentKit/SocketController.swift b/Sources/Packages/Sources/SecretAgentKit/SocketController.swift index 0c916c3..26e4c79 100644 --- a/Sources/Packages/Sources/SecretAgentKit/SocketController.swift +++ b/Sources/Packages/Sources/SecretAgentKit/SocketController.swift @@ -1,12 +1,16 @@ import Foundation import OSLog +/// A controller that manages socket configuration and request dispatching. public class SocketController { + /// The active FileHandle. private var fileHandle: FileHandle? - private var port: SocketPort? + /// A handler that will be notified when a new read/write handle is available. public var handler: ((FileHandleReader, FileHandleWriter) -> Void)? + /// Initializes a socket controller with a specified path. + /// - Parameter path: The path to use as a socket. public init(path: String) { Logger().debug("Socket controller setting up at \(path)") if let _ = try? FileManager.default.removeItem(atPath: path) { @@ -15,19 +19,23 @@ public class SocketController { let exists = FileManager.default.fileExists(atPath: path) assert(!exists) Logger().debug("Socket controller path is clear") - port = socketPort(at: path) configureSocket(at: path) Logger().debug("Socket listening at \(path)") } + /// Configures the socket and a corresponding FileHandle. + /// - Parameter path: The path to use as a socket. func configureSocket(at path: String) { - guard let port = port else { return } + let port = socketPort(at: path) fileHandle = FileHandle(fileDescriptor: port.socket, closeOnDealloc: true) NotificationCenter.default.addObserver(self, selector: #selector(handleConnectionAccept(notification:)), name: .NSFileHandleConnectionAccepted, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleConnectionDataAvailable(notification:)), name: .NSFileHandleDataAvailable, object: nil) fileHandle?.acceptConnectionInBackgroundAndNotify(forModes: [RunLoop.current.currentMode!]) } + /// Creates a SocketPort for a path. + /// - Parameter path: The path to use as a socket. + /// - Returns: A configured SocketPort. func socketPort(at path: String) -> SocketPort { var addr = sockaddr_un() addr.sun_family = sa_family_t(AF_UNIX) @@ -49,6 +57,8 @@ public class SocketController { return SocketPort(protocolFamily: AF_UNIX, socketType: SOCK_STREAM, protocol: 0, address: data)! } + /// Handles a new connection being accepted, invokes the handler, and prepares to accept new connections. + /// - Parameter notification: A `Notification` that triggered the call. @objc func handleConnectionAccept(notification: Notification) { Logger().debug("Socket controller accepted connection") guard let new = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return } @@ -57,6 +67,8 @@ public class SocketController { fileHandle?.acceptConnectionInBackgroundAndNotify(forModes: [RunLoop.current.currentMode!]) } + /// Handles a new connection providing data and invokes the handler callback. + /// - Parameter notification: A `Notification` that triggered the call. @objc func handleConnectionDataAvailable(notification: Notification) { Logger().debug("Socket controller has new data available") guard let new = notification.object as? FileHandle else { return }