Class: WifiWand::Platforms::Mac::Model
Constant Summary
collapse
- SYSTEM_PROFILER_TIMEOUT_SECONDS =
SystemProfilerWifiDataProvider::SYSTEM_PROFILER_TIMEOUT_SECONDS
- KEYCHAIN_LOOKUP_TIMEOUT_SECONDS =
KeychainPasswordReader::DEFAULT_LOOKUP_TIMEOUT_SECONDS
- SUDO_AUTH_CHECK_TIMEOUT_SECONDS =
1
- SUDO_NETWORKSETUP_TIMEOUT_SECONDS =
5
Instance Attribute Summary
Attributes inherited from BaseModel
#command_executor, #connection_manager, #connectivity_tester, #disconnect_manager, #runtime_config, #state_manager, #status_waiter, #wifi_interface
Class Method Summary
collapse
Instance Method Summary
collapse
-
#_available_network_names ⇒ Object
Returns the network names sorted in descending order of signal strength.
-
#_available_network_scan ⇒ Object
-
#_connect(network_name, password = nil) ⇒ Object
Connect mutations flow through the direct Swift-source transport path.
-
#_connected_network_name ⇒ Object
Fulfills BaseModel's abstract-method contract; BaseModel's connected_network_name wraps this with the shared wifi_on? guard.
-
#_disconnect ⇒ Object
Disconnects from the currently connected network.
-
#_ipv4_addresses ⇒ Object
-
#_ipv6_addresses ⇒ Object
-
#_preferred_network_password(preferred_network_name, timeout_in_secs: KEYCHAIN_LOOKUP_TIMEOUT_SECONDS) ⇒ Object
@return: If the network is in the preferred networks list If a password is associated w/this network, return the password If not, return nil else raise an error.
-
#associated? ⇒ Boolean
-
#available_network_scan ⇒ Object
-
#bssid ⇒ Object
-
#connected? ⇒ Boolean
-
#connection_ready?(network_name) ⇒ Boolean
-
#connection_security_type ⇒ String?
Gets the security type of the currently connected network.
-
#default_interface ⇒ Object
Returns the network interface used for default internet route on macOS.
-
#detect_wifi_interface_using_networksetup(timeout_in_secs: nil) ⇒ Object
Identifies the (first) wireless network hardware interface in the system, e.g.
-
#generate_qr_code(filespec = nil, overwrite: false, password: nil, in_stream: $stdin) ⇒ Object
-
#helper_client ⇒ Object
-
#initialize(options = {}) ⇒ Model
constructor
-
#is_wifi_interface?(interface) ⇒ Boolean
Returns whether or not the specified interface is a WiFi interface.
-
#mac_address ⇒ Object
-
#macos_version(timeout_in_secs: nil) ⇒ Object
Lazily detected macOS version to avoid OS calls during initialization.
-
#nameservers ⇒ Object
-
#nameservers_using_networksetup ⇒ Object
-
#nameservers_using_scutil ⇒ Object
-
#network_hidden? ⇒ Boolean
Checks if the currently connected network is a hidden network.
-
#network_identity_redacted? ⇒ Boolean
-
#network_identity_redaction_reason ⇒ Object
-
#open_resource(resource_url) ⇒ Object
-
#preferred_network_password(preferred_network_name, timeout_in_secs: nil) ⇒ Object
Password lookups on macOS may block on a user-facing keychain approval dialog, so the public lookup API defaults to waiting indefinitely unless a caller explicitly requests a timeout.
-
#preferred_networks ⇒ Object
Returns data pertaining to "preferred" networks, many/most of which will probably not be available.
-
#print_qr_code(password: nil) ⇒ Object
-
#probe_wifi_interface(timeout_in_secs: nil) ⇒ Object
Identifies the (first) wireless network hardware interface in the system, e.g.
-
#remove_preferred_network(network_name) ⇒ Object
-
#render_qr_code(format: :ansi, password: nil) ⇒ Object
-
#set_nameservers(nameservers) ⇒ Object
rubocop:disable Naming/AccessorMethodName.
-
#signal_quality ⇒ Object
-
#status_line_data(progress_callback: nil) ⇒ Object
-
#status_network_identity(timeout_in_secs: nil) ⇒ Object
-
#status_wifi_on?(timeout_in_secs: nil) ⇒ Boolean
-
#validate_os_preconditions(timeout_in_secs: nil) ⇒ Object
-
#wifi_info ⇒ Object
-
#wifi_off ⇒ Object
-
#wifi_on ⇒ Object
-
#wifi_on? ⇒ Boolean
-
#wifi_service_name ⇒ Object
Returns the Wi-Fi service name dynamically (e.g., "Wi-Fi", "AirPort", etc.).
Methods inherited from BaseModel
#available_network_names, #available_resources_help, #captive_portal_login_required, #capture_network_state, #command_available?, #connect, #connected_network_name, create_model, current_os_matches_this_model?, #cycle_network, #disassociated_stable?, #disconnect, #disconnect_associated?, #disconnect_stability_window_in_secs, #dns_working?, #err_stream, #err_stream=, #has_preferred_network?, inherited, #init, #init_wifi_interface, #internet_connectivity_state, #internet_tcp_connectivity?, #ipv4_addresses, #ipv6_addresses, #last_connection_used_saved_password?, #mac?, #open_resources_by_codes, #os, #out_stream, #out_stream=, #public_ip_address, #public_ip_country, #public_ip_info, #public_ip_lookup, #qr_code_generator, #random_mac_address, #remove_preferred_networks, #resource_manager, #restore_network_state, #run_command, #till, #ubuntu?, #verbose=, #verbose?, #wifi_info_builder
Methods included from Timing
monotonic_now, status_deadline, status_timeout_for
string_nil_or_blank?, string_nil_or_empty?
Constructor Details
#initialize(options = {}) ⇒ Model
Returns a new instance of Model.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 38
def initialize(options = {})
super
@macos_version = nil
@helper_client = nil
@swift_runtime = nil
@system_profiler_wifi_data_provider = nil
@dns_manager = nil
@interface_detector = nil
@wifi_service_name_source = nil
@keychain_password_reader = nil
@network_identity_reader = nil
@network_scanner = nil
@current_network_details = nil
@status_queries = nil
@system_network_info = nil
end
|
Class Method Details
.os_id ⇒ Object
94
95
96
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 94
def self.os_id
:mac
end
|
Instance Method Details
#_available_network_names ⇒ Object
Returns the network names sorted in descending order of signal strength.
139
140
141
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 139
def _available_network_names
network_scanner.available_network_names
end
|
#_available_network_scan ⇒ Object
149
150
151
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 149
def _available_network_scan
network_scanner.scan
end
|
#_connect(network_name, password = nil) ⇒ Object
Connect mutations flow through the direct Swift-source transport path.
That path owns the Swift/CoreWLAN attempt plus fallback to traditional
macOS utilities when Swift is unavailable or the connect attempt fails in
known ways.
231
232
233
234
235
236
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 231
def _connect(network_name, password = nil)
invalidate_system_profiler_wifi_data_cache
wifi_transport.connect(network_name, password)
ensure
invalidate_system_profiler_wifi_data_cache
end
|
#_connected_network_name ⇒ Object
Fulfills BaseModel's abstract-method contract; BaseModel's
connected_network_name wraps this with the shared wifi_on? guard.
307
308
309
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 307
def _connected_network_name
network_identity_reader.connected_network_name
end
|
#_disconnect ⇒ Object
Disconnects from the currently connected network. Does not turn off WiFi.
Disconnect mutations use the direct Swift-source transport path first,
with ifconfig fallback when the Swift/CoreWLAN path is unavailable or
fails.
336
337
338
339
340
341
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 336
def _disconnect
invalidate_system_profiler_wifi_data_cache
wifi_transport.disconnect
ensure
invalidate_system_profiler_wifi_data_cache
end
|
#_ipv4_addresses ⇒ Object
256
257
258
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 256
def _ipv4_addresses
system_network_info.ipv4_addresses
end
|
#_ipv6_addresses ⇒ Object
260
261
262
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 260
def _ipv6_addresses
system_network_info.ipv6_addresses
end
|
#_preferred_network_password(preferred_network_name, timeout_in_secs: KEYCHAIN_LOOKUP_TIMEOUT_SECONDS) ⇒ Object
@return:
If the network is in the preferred networks list
If a password is associated w/this network, return the password
If not, return nil
else
raise an error
251
252
253
254
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 251
def _preferred_network_password(preferred_network_name,
timeout_in_secs: KEYCHAIN_LOOKUP_TIMEOUT_SECONDS)
keychain_password_reader.password_for(preferred_network_name, timeout_in_secs: timeout_in_secs)
end
|
#associated? ⇒ Boolean
179
180
181
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 179
def associated?
network_identity_reader.associated?
end
|
#available_network_scan ⇒ Object
143
144
145
146
147
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 143
def available_network_scan
raise WifiOffError, 'WiFi is off, cannot scan for available networks.' unless wifi_on?
_available_network_scan
end
|
#bssid ⇒ Object
347
348
349
350
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 347
def bssid
result = helper_client.connected_network_bssid
result.payload
end
|
#connected? ⇒ Boolean
183
184
185
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 183
def connected?
network_identity_reader.connected?
end
|
#connection_ready?(network_name) ⇒ Boolean
56
57
58
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 56
def connection_ready?(network_name)
with_system_profiler_wifi_data_cache_scope { super }
end
|
#connection_security_type ⇒ String?
Gets the security type of the currently connected network.
536
537
538
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 536
public def connection_security_type
current_network_details.connection_security_type
end
|
#default_interface ⇒ Object
Returns the network interface used for default internet route on macOS
369
370
371
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 369
def default_interface
system_network_info.default_interface
end
|
#detect_wifi_interface_using_networksetup(timeout_in_secs: nil) ⇒ Object
Identifies the (first) wireless network hardware interface in the system, e.g. en0 or en1
This may not detect WiFi ports with nonstandard names, such as USB WiFi devices.
114
115
116
117
118
119
120
121
122
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 114
def detect_wifi_interface_using_networksetup(timeout_in_secs: nil)
result = interface_detector.detect_using_networksetup(
timeout_in_secs: timeout_in_secs,
known_interface: @wifi_interface
)
update_wifi_detection_state(result)
result.interface
end
|
#generate_qr_code(filespec = nil, overwrite: false, password: nil, in_stream: $stdin) ⇒ Object
76
77
78
79
80
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 76
def generate_qr_code(filespec = nil, overwrite: false, password: nil, in_stream: $stdin)
with_system_profiler_wifi_data_cache_scope do
super(filespec, overwrite: overwrite, password: password, in_stream: in_stream)
end
end
|
#helper_client ⇒ Object
323
324
325
326
327
328
329
330
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 323
def helper_client
@helper_client ||= WifiWand::Platforms::Mac::Helper::Client.new(
out_stream_provider: -> { out_stream },
err_stream_provider: -> { err_stream },
verbosity_provider: -> { verbose? },
macos_version_reader: ->(timeout_in_secs: nil) { macos_version(timeout_in_secs: timeout_in_secs) }
)
end
|
#is_wifi_interface?(interface) ⇒ Boolean
Returns whether or not the specified interface is a WiFi interface.
171
172
173
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 171
def is_wifi_interface?(interface)
interface_detector.is_wifi_interface?(interface)
end
|
#mac_address ⇒ Object
343
344
345
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 343
def mac_address
system_network_info.mac_address
end
|
#macos_version(timeout_in_secs: nil) ⇒ Object
Lazily detected macOS version to avoid OS calls during initialization
34
35
36
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 34
def macos_version(timeout_in_secs: nil)
@macos_version ||= system_network_info.detect_macos_version(timeout_in_secs: timeout_in_secs)
end
|
#nameservers ⇒ Object
366
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 366
def nameservers = nameservers_using_scutil
|
#nameservers_using_networksetup ⇒ Object
362
363
364
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 362
def nameservers_using_networksetup
dns_manager.nameservers_using_networksetup
end
|
#nameservers_using_scutil ⇒ Object
358
359
360
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 358
def nameservers_using_scutil
dns_manager.nameservers_using_scutil
end
|
#network_hidden? ⇒ Boolean
Checks if the currently connected network is a hidden network.
A hidden network does not broadcast its SSID.
553
554
555
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 553
public def network_hidden?
current_network_details.network_hidden?
end
|
#network_identity_redacted? ⇒ Boolean
315
316
317
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 315
def network_identity_redacted?
network_identity_reader.network_identity_redacted?
end
|
#network_identity_redaction_reason ⇒ Object
319
320
321
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 319
def network_identity_redaction_reason
network_identity_reader.network_identity_redaction_reason
end
|
#open_resource(resource_url) ⇒ Object
356
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 356
def open_resource(resource_url) = system_network_info.open_resource(resource_url)
|
#preferred_network_password(preferred_network_name, timeout_in_secs: nil) ⇒ Object
Password lookups on macOS may block on a user-facing keychain approval
dialog, so the public lookup API defaults to waiting indefinitely unless
a caller explicitly requests a timeout.
241
242
243
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 241
def preferred_network_password(preferred_network_name, timeout_in_secs: nil)
super
end
|
#preferred_networks ⇒ Object
Returns data pertaining to "preferred" networks, many/most of which will probably not be available.
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 154
def preferred_networks
iface = wifi_interface
lines = run_command(
['networksetup', '-listpreferredwirelessnetworks', iface]
).stdout.split("\n")
lines.delete_at(0) lines.map! { |line| line.gsub("\t", '') } lines.sort! { |s1, s2| s1.casecmp(s2) } lines
end
|
#print_qr_code(password: nil) ⇒ Object
88
89
90
91
92
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 88
def print_qr_code(password: nil)
with_system_profiler_wifi_data_cache_scope do
super(password: password)
end
end
|
#probe_wifi_interface(timeout_in_secs: nil) ⇒ Object
Identifies the (first) wireless network hardware interface in the system, e.g. en0 or en1
Prefer the faster networksetup path and fall back to system_profiler if needed.
This may not detect WiFi ports with nonstandard names, such as USB WiFi devices.
127
128
129
130
131
132
133
134
135
136
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 127
def probe_wifi_interface(timeout_in_secs: nil)
result = interface_detector.probe(
timeout_in_secs: timeout_in_secs,
known_interface: @wifi_interface,
known_service_name: @wifi_service_name
)
update_wifi_detection_state(result)
result.interface
end
|
#remove_preferred_network(network_name) ⇒ Object
264
265
266
267
268
269
270
271
272
273
274
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 264
def remove_preferred_network(network_name)
network_name = network_name.to_s
iface = wifi_interface
ensure_sudo_authenticated_for_preferred_network_removal!
run_command(
['sudo', 'networksetup', '-removepreferredwirelessnetwork', iface, network_name],
raise_on_error: true,
timeout_in_secs: SUDO_NETWORKSETUP_TIMEOUT_SECONDS
)
[network_name]
end
|
#render_qr_code(format: :ansi, password: nil) ⇒ Object
82
83
84
85
86
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 82
def render_qr_code(format: :ansi, password: nil)
with_system_profiler_wifi_data_cache_scope do
super(format: format, password: password)
end
end
|
#set_nameservers(nameservers) ⇒ Object
rubocop:disable Naming/AccessorMethodName
352
353
354
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 352
def set_nameservers(nameservers) dns_manager.set_nameservers(nameservers)
end
|
#signal_quality ⇒ Object
540
541
542
543
544
545
546
547
548
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 540
public def signal_quality
helper_result = helper_client.connected_network_name
return helper_result.signal_quality if helper_result.signal_quality
return nil if helper_result.not_connected?
current_network_details.signal_quality
rescue WifiWand::Error
current_network_details.signal_quality
end
|
#status_line_data(progress_callback: nil) ⇒ Object
#status_network_identity(timeout_in_secs: nil) ⇒ Object
187
188
189
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 187
def status_network_identity(timeout_in_secs: nil)
status_queries.status_network_identity(timeout_in_secs: timeout_in_secs)
end
|
#status_wifi_on?(timeout_in_secs: nil) ⇒ Boolean
191
192
193
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 191
def status_wifi_on?(timeout_in_secs: nil)
status_queries.status_wifi_on?(timeout_in_secs: timeout_in_secs)
end
|
#validate_os_preconditions(timeout_in_secs: nil) ⇒ Object
373
374
375
376
377
378
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 373
def validate_os_preconditions(timeout_in_secs: nil)
:ok
end
|
#wifi_info ⇒ Object
60
61
62
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 60
def wifi_info
with_system_profiler_wifi_data_cache_scope { wifi_info_builder.build }
end
|
#wifi_off ⇒ Object
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 212
def wifi_off
return unless wifi_on?
invalidate_system_profiler_wifi_data_cache
begin
iface = wifi_interface
run_command(['networksetup', '-setairportpower', iface, 'off'])
ensure
invalidate_system_profiler_wifi_data_cache
end
wifi_on? ? raise(WifiDisableError) : nil
end
|
#wifi_on ⇒ Object
196
197
198
199
200
201
202
203
204
205
206
207
208
209
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 196
def wifi_on
return if wifi_on?
invalidate_system_profiler_wifi_data_cache
begin
iface = wifi_interface
run_command(['networksetup', '-setairportpower', iface, 'on'])
ensure
invalidate_system_profiler_wifi_data_cache
end
wifi_on? ? nil : raise(WifiEnableError)
end
|
#wifi_on? ⇒ Boolean
175
176
177
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 175
def wifi_on?
system_network_info.wifi_on?
end
|
#wifi_service_name ⇒ Object
Returns the Wi-Fi service name dynamically (e.g., "Wi-Fi", "AirPort", etc.)
99
100
101
102
103
104
105
106
107
108
109
110
|
# File 'lib/wifi_wand/platforms/mac/model.rb', line 99
def wifi_service_name
return @wifi_service_name if @wifi_service_name && !@wifi_service_name.empty?
service_name = interface_detector.detected_wifi_service_name(known_interface: @wifi_interface)
if service_name && !service_name.empty?
@wifi_service_name_source = :detected
@wifi_service_name = service_name
else
@wifi_service_name_source = :fallback
@wifi_service_name = 'Wi-Fi'
end
end
|