Class: WifiWand::MacOsModel
- Defined in:
- lib/wifi-wand/models/mac_os_model.rb
Instance Attribute Summary
Attributes inherited from BaseModel
#verbose_mode, #wifi_interface
Instance Method Summary collapse
-
#available_network_names ⇒ Object
Returns the network names sorted in descending order of signal strength.
-
#connected_network_name ⇒ Object
Returns the network currently connected to, or nil if none.
-
#detect_wifi_interface ⇒ Object
Identifies the (first) wireless network hardware interface in the system, e.g.
-
#detect_wifi_interface_using_networksetup ⇒ Object
Identifies the (first) wireless network hardware interface in the system, e.g.
-
#disconnect ⇒ Object
Disconnects from the currently connected network.
- #ensure_swift_and_corewlan_present ⇒ Object
-
#initialize(options = OpenStruct.new) ⇒ MacOsModel
constructor
Takes an OpenStruct containing options such as verbose mode and interface name.
-
#ip_address ⇒ Object
Returns the IP address assigned to the wifi interface, or nil if none.
-
#is_wifi_interface?(interface) ⇒ Boolean
Returns whether or not the specified interface is a WiFi interface.
-
#mac_address ⇒ Object
TODO: Add capability to change the MAC address using a command in the form of: sudo ifconfig en0 ether aa:bb:cc:dd:ee:ff However, the MAC address will be set to the real hardware address on restart.
- #nameservers_using_networksetup ⇒ Object
-
#nameservers_using_resolv_conf ⇒ Object
Though this is strictly not OS-agnostic, it will be used by most OS’s, and can be overridden by subclasses (e.g. Windows).
- #nameservers_using_scutil ⇒ Object
- #open_application(application_name) ⇒ Object
- #open_resource(resource_url) ⇒ Object
- #os_level_connect(network_name, password = nil) ⇒ Object
-
#os_level_connect_using_networksetup(network_name, password = nil) ⇒ Object
This method is called by BaseModel#connect to do the OS-specific connection logic.
- #os_level_connect_using_swift(network_name, password = nil) ⇒ Object
-
#os_level_preferred_network_password(preferred_network_name) ⇒ 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.
-
#preferred_networks ⇒ Object
Returns data pertaining to “preferred” networks, many/most of which will probably not be available.
- #remove_preferred_network(network_name) ⇒ Object
- #run_swift_command(basename, *args) ⇒ Object
- #set_nameservers(nameservers) ⇒ Object
- #swift_and_corewlan_present? ⇒ Boolean
-
#wifi_info ⇒ Object
Returns some useful wifi-related information.
-
#wifi_off ⇒ Object
Turns wifi off.
-
#wifi_on ⇒ Object
Turns wifi on.
-
#wifi_on? ⇒ Boolean
Returns true if wifi is on, else false.
Methods inherited from BaseModel
#connect, #connected_to?, #connected_to_internet?, #cycle_network, #preferred_network_password, #public_ip_address_info, #random_mac_address, #remove_preferred_networks, #run_os_command, #till, #try_os_command_until
Constructor Details
#initialize(options = OpenStruct.new) ⇒ MacOsModel
Takes an OpenStruct containing options such as verbose mode and interface name.
13 14 15 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 13 def initialize( = OpenStruct.new) super end |
Instance Method Details
#available_network_names ⇒ Object
Returns the network names sorted in descending order of signal strength.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 53 def available_network_names return nil unless wifi_on? # no need to try # run_swift_command('AvailableWifiNetworkLister').split("\n").uniq json_text = run_os_command('system_profiler -json SPAirPortDataType') data = JSON.parse(json_text) inner_key = connected_network_name ? 'spairport_airport_other_local_wireless_networks' : 'spairport_airport_local_wireless_networks' nets = data['SPAirPortDataType'] \ .detect { |h| h.key?('spairport_airport_interfaces') } \ ['spairport_airport_interfaces'] \ .detect { |h| h['_name'] == wifi_interface } \ [inner_key] \ .sort_by { |net| -net['spairport_signal_noise'].split('/').first.to_i } nets.map { |h| h['_name']}.uniq end |
#connected_network_name ⇒ Object
Returns the network currently connected to, or nil if none.
186 187 188 189 190 191 192 193 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 186 def connected_network_name return nil unless wifi_on? # no need to try command_output = run_os_command("ipconfig getsummary #{wifi_interface} | grep ' SSID :'", false) return nil if command_output.empty? command_output.split('SSID :').last.strip end |
#detect_wifi_interface ⇒ 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.
44 45 46 47 48 49 50 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 44 def detect_wifi_interface json_text = run_os_command('system_profiler -json SPNetworkDataType') net_data = JSON.parse(json_text) nets = net_data['SPNetworkDataType'] wifi = nets.detect { |net| net['_name'] == 'Wi-Fi'} wifi['interface'] end |
#detect_wifi_interface_using_networksetup ⇒ 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.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 19 def detect_wifi_interface_using_networksetup lines = run_os_command("networksetup -listallhardwareports").split("\n") # Produces something like this: # Hardware Port: Wi-Fi # Device: en0 # Ethernet Address: ac:bc:32:b9:a9:9d # # Hardware Port: Bluetooth PAN # Device: en3 # Ethernet Address: ac:bc:32:b9:a9:9e wifi_interface_line_num = (0...lines.size).detect do |index| /: Wi-Fi$/.match(lines[index]) end if wifi_interface_line_num.nil? raise Error.new(%Q{Wifi interface (e.g. "en0") not found in output of: networksetup -listallhardwareports}) else lines[wifi_interface_line_num + 1].split(': ').last end end |
#disconnect ⇒ Object
Disconnects from the currently connected network. Does not turn off wifi.
197 198 199 200 201 202 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 197 def disconnect return nil unless wifi_on? # no need to try run_swift_command('WifiNetworkDisconecter') nil end |
#ensure_swift_and_corewlan_present ⇒ Object
331 332 333 334 335 336 337 338 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 331 def ensure_swift_and_corewlan_present unless swift_and_corewlan_present? raise RuntimeError, " Swift and/or CoreWLAN are not present and are needed by this task.\n This can be fixed by installing XCode.\n MESSAGE\n end\nend\n" |
#ip_address ⇒ Object
Returns the IP address assigned to the wifi interface, or nil if none.
164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 164 def ip_address return nil unless wifi_on? # no need to try begin run_os_command("ipconfig getifaddr #{wifi_interface}").chomp rescue OsCommandError => error if error.exitstatus == 1 nil else raise end end end |
#is_wifi_interface?(interface) ⇒ Boolean
Returns whether or not the specified interface is a WiFi interface.
89 90 91 92 93 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 89 def is_wifi_interface?(interface) run_os_command("networksetup -listpreferredwirelessnetworks #{interface} 2>/dev/null") exit_status = $?.exitstatus exit_status != 10 end |
#mac_address ⇒ Object
TODO: Add capability to change the MAC address using a command in the form of:
sudo ifconfig en0 ether aa:bb:cc:dd:ee:ff
However, the MAC address will be set to the real hardware address on restart. One way to implement this is to have an optional address argument, then this method returns the current address if none is provided, but sets to the specified address if it is.
211 212 213 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 211 def mac_address run_os_command("ifconfig #{wifi_interface} | awk '/ether/{print $2}'").chomp end |
#nameservers_using_networksetup ⇒ Object
323 324 325 326 327 328 329 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 323 def nameservers_using_networksetup output = run_os_command("networksetup -getdnsservers Wi-Fi") if output == "There aren't any DNS Servers set on Wi-Fi.\n" output = '' end output.split("\n") end |
#nameservers_using_resolv_conf ⇒ Object
Though this is strictly not OS-agnostic, it will be used by most OS’s, and can be overridden by subclasses (e.g. Windows).
305 306 307 308 309 310 311 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 305 def nameservers_using_resolv_conf begin File.readlines('/etc/resolv.conf').grep(/^nameserver /).map { |line| line.split.last } rescue Errno::ENOENT nil end end |
#nameservers_using_scutil ⇒ Object
314 315 316 317 318 319 320 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 314 def nameservers_using_scutil output = run_os_command('scutil --dns') nameserver_lines_scoped_and_unscoped = output.split("\n").grep(/^\s*nameserver\[/) unique_nameserver_lines = nameserver_lines_scoped_and_unscoped.uniq # take the union nameservers = unique_nameserver_lines.map { |line| line.split(' : ').last.strip } nameservers end |
#open_application(application_name) ⇒ Object
276 277 278 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 276 def open_application(application_name) run_os_command('open -a ' + application_name) end |
#open_resource(resource_url) ⇒ Object
281 282 283 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 281 def open_resource(resource_url) run_os_command('open ' + resource_url) end |
#os_level_connect(network_name, password = nil) ⇒ Object
138 139 140 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 138 def os_level_connect(network_name, password = nil) os_level_connect_using_swift(network_name, password) end |
#os_level_connect_using_networksetup(network_name, password = nil) ⇒ Object
This method is called by BaseModel#connect to do the OS-specific connection logic.
123 124 125 126 127 128 129 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 123 def os_level_connect_using_networksetup(network_name, password = nil) command = "networksetup -setairportnetwork #{wifi_interface} #{Shellwords.shellescape(network_name)}" if password command << ' ' << Shellwords.shellescape(password) end run_os_command(command) end |
#os_level_connect_using_swift(network_name, password = nil) ⇒ Object
131 132 133 134 135 136 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 131 def os_level_connect_using_swift(network_name, password = nil) ensure_swift_and_corewlan_present args = [Shellwords.shellescape(network_name)] args << Shellwords.shellescape(password) if password run_swift_command('WifiNetworkConnecter', *args) end |
#os_level_preferred_network_password(preferred_network_name) ⇒ 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
149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 149 def os_level_preferred_network_password(preferred_network_name) command = %Q{security find-generic-password -D "AirPort network password" -a "#{preferred_network_name}" -w 2>&1} begin return run_os_command(command).chomp rescue OsCommandError => error if error.exitstatus == 44 # network has no password stored nil else raise end end end |
#preferred_networks ⇒ Object
Returns data pertaining to “preferred” networks, many/most of which will probably not be available.
74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 74 def preferred_networks lines = run_os_command("networksetup -listpreferredwirelessnetworks #{wifi_interface}").split("\n") # Produces something like this, unsorted, and with leading tabs: # Preferred networks on en0: # LibraryWiFi # @thePAD/Magma lines.delete_at(0) # remove title line lines.map! { |line| line.gsub("\t", '') } # remove leading tabs lines.sort! { |s1, s2| s1.casecmp(s2) } # sort alphabetically, case insensitively lines end |
#remove_preferred_network(network_name) ⇒ Object
178 179 180 181 182 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 178 def remove_preferred_network(network_name) network_name = network_name.to_s run_os_command("sudo networksetup -removepreferredwirelessnetwork " + "#{wifi_interface} #{Shellwords.shellescape(network_name)}") end |
#run_swift_command(basename, *args) ⇒ Object
345 346 347 348 349 350 351 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 345 def run_swift_command(basename, *args) ensure_swift_and_corewlan_present swift_filespec = File.absolute_path(File.join(File.dirname(__FILE__), "../../../swift/#{basename}.swift")) argv = ['swift', swift_filespec] + args command = argv.compact.join(' ') run_os_command(command) end |
#set_nameservers(nameservers) ⇒ Object
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 251 def set_nameservers(nameservers) arg = if nameservers == :clear 'empty' else bad_addresses = nameservers.reject do |ns| begin IPAddr.new(ns).ipv4? true rescue => e puts e false end end unless bad_addresses.empty? raise Error.new("Bad IP addresses provided: #{bad_addresses.join(', ')}") end nameservers.join(' ') end # end assignment to arg variable run_os_command("networksetup -setdnsservers Wi-Fi #{arg}") nameservers end |
#swift_and_corewlan_present? ⇒ Boolean
340 341 342 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 340 def swift_and_corewlan_present? system("swift -e 'import CoreWLAN' >/dev/null 2>&1") end |
#wifi_info ⇒ Object
Returns some useful wifi-related information.
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 217 def wifi_info connected = begin connected_to_internet? rescue false end info = { 'wifi_on' => wifi_on?, 'internet_on' => connected, 'interface' => wifi_interface, 'network' => connected_network_name, 'ip_address' => ip_address, 'mac_address' => mac_address, 'nameservers' => nameservers_using_scutil, 'timestamp' => Time.now, } if info['internet_on'] begin info['public_ip'] = public_ip_address_info rescue => e puts " \#{e.class} obtaining public IP address info, proceeding with everything else. Error message:\n \#{e}\n\n MESSAGE\n end\n end\n info\nend\n" |
#wifi_off ⇒ Object
Turns wifi off.
113 114 115 116 117 118 119 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 113 def wifi_off return unless wifi_on? run_os_command("networksetup -setairportpower #{wifi_interface} off") wifi_on? ? Error.new(raise("Wifi could not be disabled.")) : nil end |
#wifi_on ⇒ Object
Turns wifi on.
104 105 106 107 108 109 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 104 def wifi_on return if wifi_on? run_os_command("networksetup -setairportpower #{wifi_interface} on") wifi_on? ? nil : Error.new(raise("Wifi could not be enabled.")) end |
#wifi_on? ⇒ Boolean
Returns true if wifi is on, else false.
97 98 99 100 |
# File 'lib/wifi-wand/models/mac_os_model.rb', line 97 def wifi_on? output = run_os_command("networksetup -getairportpower #{wifi_interface}") output.chomp.match?(/\): On$/) end |