import CoreWLAN import Foundation private struct AssociationRequest: Decodable { let ssid: String let password: String } private struct AssociationResponse: Encodable { let ok: Bool let alreadyAssociated: Bool? let reasonCode: String? enum CodingKeys: String, CodingKey { case ok case alreadyAssociated = "already_associated" case reasonCode = "reason_code" } } private func emit(_ response: AssociationResponse, exitCode: Int32) -> Never { let encoder = JSONEncoder() if let data = try? encoder.encode(response) { FileHandle.standardOutput.write(data) } exit(exitCode) } private let input = FileHandle.standardInput.readDataToEndOfFile() guard input.count <= 1024 else { emit( AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "request-too-large"), exitCode: 1 ) } do { let request = try JSONDecoder().decode(AssociationRequest.self, from: input) guard let ssidData = request.ssid.data(using: .utf8), (1 ... 32).contains(ssidData.count), let passwordData = request.password.data(using: .utf8), (1 ... 64).contains(passwordData.count) else { emit( AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "credential-bounds"), exitCode: 1 ) } guard let interface = CWWiFiClient.shared().interface() else { emit( AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "wifi-interface-unavailable"), exitCode: 1 ) } if interface.ssid() == request.ssid { emit(AssociationResponse(ok: true, alreadyAssociated: true, reasonCode: nil), exitCode: 0) } let networks = try interface.scanForNetworks(withSSID: ssidData) guard let network = networks.first(where: { $0.ssid == request.ssid }) else { emit( AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "network-not-found"), exitCode: 1 ) } try interface.associate(to: network, password: request.password) // CoreWLAN's synchronous association call throws on failure. Reading the // current SSID again would require Location authorization on recent macOS // versions and could turn a successful association into a false negative. emit(AssociationResponse(ok: true, alreadyAssociated: false, reasonCode: nil), exitCode: 0) } catch { emit( AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "corewlan-error"), exitCode: 1 ) }