diff --git a/Mac.Tests/Mac.Tests.csproj b/Mac.Tests/Mac.Tests.csproj index 96b25704..45c6605b 100644 --- a/Mac.Tests/Mac.Tests.csproj +++ b/Mac.Tests/Mac.Tests.csproj @@ -14,6 +14,6 @@ - + \ No newline at end of file diff --git a/Mac.Tests/MacSignalParserTests.cs b/Mac.Tests/MacSignalParserTests.cs index 5f08e7c4..a32ffd06 100644 --- a/Mac.Tests/MacSignalParserTests.cs +++ b/Mac.Tests/MacSignalParserTests.cs @@ -16,59 +16,34 @@ public async Task ResultsAreParsedIntoSignals() //arrange var logger = Substitute.For(); var signalParser = new MacSignalParser(logger); - var contents = await File.ReadAllTextAsync("airport-output.txt"); + var contents = await File.ReadAllTextAsync("system_profiler-output.txt"); //act var signals = signalParser.Parse(contents).ToList(); //assert Assert.Equal("net1", signals[0].SSID); - Assert.Equal("xx:bf:xx:f7:13:xx", signals[0].MAC); + Assert.Empty(signals[0].MAC); Assert.Equal(Frequency._2_4_GHz, signals[0].Frequency); - Assert.Equal(11, signals[0].Channel); - Assert.Equal(-83, signals[0].Strength); + Assert.Equal(9, signals[0].Channel); + Assert.Equal(-39, signals[0].Strength); Assert.Equal("ssid🏎2", signals[1].SSID); - Assert.Equal("xx:3d:xx:96:97:xx", signals[1].MAC); + Assert.Empty(signals[1].MAC); Assert.Equal(Frequency._5_GHz, signals[1].Frequency); - Assert.Equal(149, signals[1].Channel); - Assert.Equal(-82, signals[1].Strength); + Assert.Equal(44, signals[1].Channel); + Assert.Equal(-50, signals[1].Strength); Assert.Equal("access_point_3", signals[2].SSID); - Assert.Equal("xx:3d:xx:96:98:xx", signals[2].MAC); - Assert.Equal(Frequency._2_4_GHz, signals[2].Frequency); - Assert.Equal(11, signals[2].Channel); - Assert.Equal(-76, signals[2].Strength); + Assert.Empty(signals[2].MAC); + Assert.Equal(Frequency._5_GHz, signals[2].Frequency); + Assert.Equal(149, signals[2].Channel); + Assert.Equal(-42, signals[2].Strength); Assert.Equal("wap-4", signals[3].SSID); - Assert.Equal("xx:cb:xx:ad:a8:xx", signals[3].MAC); + Assert.Empty(signals[3].MAC); Assert.Equal(Frequency._2_4_GHz, signals[3].Frequency); - Assert.Equal(6, signals[3].Channel); - Assert.Equal(-37, signals[3].Strength); - - Assert.Equal("router5", signals[4].SSID); - Assert.Equal("xx:cb:xx:ad:a8:xx", signals[4].MAC); - Assert.Equal(Frequency._5_GHz, signals[4].Frequency); - Assert.Equal(149, signals[4].Channel); - Assert.Equal(-42, signals[4].Strength); - } - - [Fact] - public async Task IgnoresInvalidResults() - { - //arrange - var logger = Substitute.For(); - var signalParser = new MacSignalParser(logger); - var contents = await File.ReadAllTextAsync("airport-output.txt"); - contents = contents - .Replace("13:xx", "") - .Replace("97:xx", "") - .Replace("a8:xx", ""); - - //act - var signals = signalParser.Parse(contents); - - //assert - Assert.Equal("access_point_3", signals.Single().SSID); + Assert.Equal(11, signals[3].Channel); + Assert.Equal(-90, signals[3].Strength); } } \ No newline at end of file diff --git a/Mac.Tests/airport-output.txt b/Mac.Tests/airport-output.txt deleted file mode 100644 index e9abd230..00000000 --- a/Mac.Tests/airport-output.txt +++ /dev/null @@ -1,6 +0,0 @@ - SSID BSSID RSSI CHANNEL HT CC SECURITY (auth/unicast/group) - net1 xx:bf:xx:f7:13:xx -83 11 Y -- WPA2(PSK/AES/AES) - ssid🏎2 xx:3d:xx:96:97:xx -82 149 Y US WPA2(PSK/AES/AES) - access_point_3 xx:3d:xx:96:98:xx -76 11 Y US WPA2(PSK/AES/AES) - wap-4 xx:cb:xx:ad:a8:xx -37 6 Y US WPA2(PSK/AES/AES) - router5 xx:cb:xx:ad:a8:xx -42 149 Y US WPA2(PSK/AES/AES) diff --git a/Mac.Tests/system_profiler-output.txt b/Mac.Tests/system_profiler-output.txt new file mode 100644 index 00000000..5cccb935 --- /dev/null +++ b/Mac.Tests/system_profiler-output.txt @@ -0,0 +1,162 @@ +{ + "SPAirPortDataType" : [ + { + "spairport_airport_interfaces" : [ + { + "_name" : "en0", + "spairport_airport_other_local_wireless_networks" : [ + { + "_name" : "net1", + "spairport_network_channel" : "9 (2GHz, 40MHz)", + "spairport_network_phymode" : "802.11", + "spairport_network_type" : "spairport_network_type_station", + "spairport_security_mode" : "pairport_security_mode_wpa3_transition", + "spairport_signal_noise" : "-39 dBm / -90 dBm" + }, + { + "_name" : "ssid🏎2", + "spairport_network_channel" : "44 (5GHz, 80MHz)", + "spairport_network_phymode" : "802.11", + "spairport_network_type" : "spairport_network_type_station", + "spairport_security_mode" : "pairport_security_mode_wpa3_transition", + "spairport_signal_noise" : "-50 dBm / -90 dBm" + }, + { + "_name" : "access_point_3", + "spairport_network_channel" : "149 (5GHz, 80MHz)", + "spairport_network_phymode" : "802.11", + "spairport_network_type" : "spairport_network_type_station", + "spairport_security_mode" : "pairport_security_mode_wpa3_transition", + "spairport_signal_noise" : "-42 dBm / -90 dBm" + }, + { + "_name" : "wap-4", + "spairport_network_channel" : "11 (2GHz, 40MHz)", + "spairport_network_phymode" : "802.11", + "spairport_network_type" : "spairport_network_type_station", + "spairport_security_mode" : "spairport_security_mode_wpa2_personal", + "spairport_signal_noise" : "-90 dBm / -90 dBm" + } + ], + "spairport_caps_airdrop" : "spairport_caps_supported", + "spairport_caps_autounlock" : "spairport_caps_supported", + "spairport_caps_wow" : "spairport_caps_supported", + "spairport_current_network_information" : { + "_name" : "net1", + "spairport_network_channel" : "149 (5GHz, 80MHz)", + "spairport_network_country_code" : "US", + "spairport_network_mcs" : 7, + "spairport_network_phymode" : "802.11ac", + "spairport_network_rate" : 975, + "spairport_network_type" : "spairport_network_type_station", + "spairport_security_mode" : "pairport_security_mode_wpa3_transition", + "spairport_signal_noise" : "-48 dBm / -90 dBm" + }, + "spairport_status_information" : "spairport_status_connected", + "spairport_supported_channels" : [ + "1 (2GHz)", + "2 (2GHz)", + "3 (2GHz)", + "4 (2GHz)", + "5 (2GHz)", + "6 (2GHz)", + "7 (2GHz)", + "8 (2GHz)", + "9 (2GHz)", + "10 (2GHz)", + "11 (2GHz)", + "12 (2GHz)", + "13 (2GHz)", + "36 (5GHz)", + "40 (5GHz)", + "44 (5GHz)", + "48 (5GHz)", + "52 (5GHz)", + "56 (5GHz)", + "60 (5GHz)", + "64 (5GHz)", + "100 (5GHz)", + "104 (5GHz)", + "108 (5GHz)", + "112 (5GHz)", + "116 (5GHz)", + "120 (5GHz)", + "124 (5GHz)", + "128 (5GHz)", + "132 (5GHz)", + "136 (5GHz)", + "140 (5GHz)", + "144 (5GHz)", + "149 (5GHz)", + "153 (5GHz)", + "157 (5GHz)", + "161 (5GHz)", + "165 (5GHz)" + ], + "spairport_supported_phymodes" : "802.11 a/b/g/n/ac", + "spairport_wireless_card_type" : "spairport_wireless_card_type_wifi (0x14E4, 0x7BF)", + "spairport_wireless_country_code" : "US", + "spairport_wireless_firmware_version" : "wl0: Jul 10 2023 12:30:19 version 9.30.503.0.32.5.92 FWID 01-88a8883", + "spairport_wireless_locale" : "ETSI", + "spairport_wireless_mac_address" : "f0:18:98:2b:b7:78" + }, + { + "_name" : "awdl0", + "spairport_current_network_information" : { + "spairport_network_type" : "spairport_network_type_station" + }, + "spairport_supported_channels" : [ + "1 (2GHz)", + "2 (2GHz)", + "3 (2GHz)", + "4 (2GHz)", + "5 (2GHz)", + "6 (2GHz)", + "7 (2GHz)", + "8 (2GHz)", + "9 (2GHz)", + "10 (2GHz)", + "11 (2GHz)", + "12 (2GHz)", + "13 (2GHz)", + "36 (5GHz)", + "40 (5GHz)", + "44 (5GHz)", + "48 (5GHz)", + "52 (5GHz)", + "56 (5GHz)", + "60 (5GHz)", + "64 (5GHz)", + "100 (5GHz)", + "104 (5GHz)", + "108 (5GHz)", + "112 (5GHz)", + "116 (5GHz)", + "120 (5GHz)", + "124 (5GHz)", + "128 (5GHz)", + "132 (5GHz)", + "136 (5GHz)", + "140 (5GHz)", + "144 (5GHz)", + "149 (5GHz)", + "153 (5GHz)", + "157 (5GHz)", + "161 (5GHz)", + "165 (5GHz)" + ], + "spairport_wireless_mac_address" : "5e:01:d5:ed:24:a0" + } + ], + "spairport_software_information" : { + "spairport_corewlan_version" : "16.0 (1657)", + "spairport_corewlankit_version" : "16.0 (1657)", + "spairport_diagnostics_version" : "11.0 (1163)", + "spairport_extra_version" : "17.0 (1728)", + "spairport_family_version" : "12.0 (1200.13.0)", + "spairport_profiler_version" : "15.0 (1502)", + "spairport_utility_version" : "6.3.9 (639.23)" + } + } + ] +} \ No newline at end of file diff --git a/Mac/MacSignalParser.cs b/Mac/MacSignalParser.cs index b5092823..c8e007ed 100644 --- a/Mac/MacSignalParser.cs +++ b/Mac/MacSignalParser.cs @@ -1,4 +1,5 @@ using System.Text; +using System.Text.Json; using WiFiSurveyor.Core; namespace WiFiSurveyor.Mac; @@ -11,39 +12,47 @@ public MacSignalParser(ILogger logger) => _logger = logger; public IReadOnlyList Parse(string results) - => results.Split("\n", StringSplitOptions.RemoveEmptyEntries) - .Skip(1) - .Select(line => GetSignal(Encoding.UTF8.GetBytes(line))) + => JsonSerializer.Deserialize(results) + .GetProperty("SPAirPortDataType").EnumerateArray().First() + .GetProperty("spairport_airport_interfaces").EnumerateArray().First() + .GetProperty("spairport_airport_other_local_wireless_networks").EnumerateArray() + .Select(j => GetSignal(j)) .Where(s => s is not null) .Cast() .ToArray(); - private Signal? GetSignal(ReadOnlySpan line) + private Signal? GetSignal(JsonElement json) { try { - return new() + return new Signal { - SSID = Encoding.UTF8.GetString(line[..32]).Trim(), - MAC = Encoding.UTF8.GetString(line[32..50]).Trim(), - Strength = short.Parse(Encoding.UTF8.GetString(line[50..55]).Trim()), - Channel = GetChannel(Encoding.UTF8.GetString(line[55..64]).Trim()), - Frequency = GetFrequency(Encoding.UTF8.GetString(line[55..64]).Trim()) + SSID = GetString(json, "_name"), + MAC = string.Empty, + Strength = GetStrength(GetString(json, "spairport_signal_noise")), + Channel = GetChannel(GetString(json, "spairport_network_channel")), + Frequency = GetFrequency(GetString(json, "spairport_network_channel")) }; } catch (Exception e) { - _logger.LogIf(LogLevel.Warning, "{now}: Could not parse signal data -- {data}", DateTime.Now, Encoding.UTF8.GetString(line)); + _logger.LogIf(LogLevel.Warning, "{now}: Could not parse signal data -- {data}", DateTime.Now, json.ToString()); _logger.LogIf(LogLevel.Debug, "{exception}", e.ToString()); return null; } } - private static Frequency GetFrequency(string column) - => GetChannel(column) < 32 + private static string GetString(JsonElement json, string property) + => json.GetProperty(property).GetString() ?? string.Empty; + + private static short GetStrength(string value) + => short.Parse(value.Split(' ')[0]); + + private static Frequency GetFrequency(string value) + => GetChannel(value) < 32 ? Frequency._2_4_GHz : Frequency._5_GHz; - private static byte GetChannel(string column) - => byte.Parse(column.Split(',')[0]); + private static byte GetChannel(string value) + => byte.Parse(value.Split(' ')[0]); } \ No newline at end of file diff --git a/Mac/MacSignalReader.cs b/Mac/MacSignalReader.cs index 6d6f65d1..96e47957 100644 --- a/Mac/MacSignalReader.cs +++ b/Mac/MacSignalReader.cs @@ -9,5 +9,5 @@ public MacSignalReader(ICommandService commandService) : base(commandService) { } - protected override ProcessStartInfo Info => new("/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport", " -s"); + protected override ProcessStartInfo Info => new("system_profiler", "SPAirPortDataType -detailLevel full -json"); } \ No newline at end of file