wifi-wand 2.10.1 → 2.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/RELEASE_NOTES.md +6 -0
- data/lib/wifi-wand/command_line_interface.rb +30 -23
- data/lib/wifi-wand/error.rb +4 -0
- data/lib/wifi-wand/main.rb +4 -2
- data/lib/wifi-wand/models/base_model.rb +19 -21
- data/lib/wifi-wand/models/helpers/command_output_formatter.rb +18 -0
- data/lib/wifi-wand/models/mac_os_model.rb +73 -22
- data/lib/wifi-wand/models/model_validator.rb +60 -0
- data/lib/wifi-wand/operating_systems.rb +4 -3
- data/lib/wifi-wand/version.rb +1 -1
- data/wifi-wand.gemspec +2 -2
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f21e7e9af16e0eea5c7d254ef75ce061fbae1ada6c707201a189ec78f9238be
|
4
|
+
data.tar.gz: ec4b2ef369ca6e3186fe02b59e57c059f89a17b03eba2cdf760035b93fdaa9b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a86d2fd563801ca4a3259d200de197d8811c6f46360a805b85779fc488107045c8df20f6013c69866b61bdddcc40f11ff77a338bb2e0984eef8690d86a2016fd
|
7
|
+
data.tar.gz: cd16ad95aed459d769e51539a911797f004be30e7ad9dfab8c6352d2aaa226cbadcbe46d5d0c4075c58b6f478bb1ccb3f6a66408aa932b1111cf0205d5ea2e3c
|
data/RELEASE_NOTES.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## v2.11.0
|
2
|
+
|
3
|
+
* Various fixes and clarifications.
|
4
|
+
* Change implementation of available_network_names to use REXML; first implemented w/position number, then XPath.
|
5
|
+
* Add attempt count to try_os_command_until in verbose mode.
|
6
|
+
|
1
7
|
## v2.10.1
|
2
8
|
|
3
9
|
* Fix egregious bug; the 'a' command did not work if `airport` was not in the path; I should have been using the AIRPORT_CMD constant but hard coded `airport` instead.
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'operating_systems'
|
2
2
|
require 'ostruct'
|
3
|
+
require_relative 'error'
|
3
4
|
require_relative 'version'
|
4
5
|
|
5
6
|
module WifiWand
|
@@ -79,11 +80,11 @@ ro[pen] - open resource (#{OPEN_RESOURCES.help_string})
|
|
79
80
|
t[ill] - returns when the desired Internet connection state is true. Options:
|
80
81
|
1) 'on'/:on, 'off'/:off, 'conn'/:conn, or 'disc'/:disc
|
81
82
|
2) wait interval, in seconds (optional, defaults to 0.5 seconds)
|
82
|
-
w[
|
83
|
+
w[ifi_on] - is the wifi on?
|
83
84
|
x[it] - exits this program (interactive shell mode only) (see also 'q')
|
84
85
|
|
85
86
|
When in interactive shell mode:
|
86
|
-
*
|
87
|
+
* remember to quote string literals.
|
87
88
|
* for pry commands, use prefix `%`.
|
88
89
|
|
89
90
|
"
|
@@ -91,7 +92,7 @@ When in interactive shell mode:
|
|
91
92
|
def initialize(options)
|
92
93
|
@options = options
|
93
94
|
current_os = OperatingSystems.new.current_os
|
94
|
-
raise "Could not determine operating system" if current_os.nil?
|
95
|
+
raise Error.new("Could not determine operating system") if current_os.nil?
|
95
96
|
model_options = OpenStruct.new({
|
96
97
|
verbose: options.verbose,
|
97
98
|
wifi_port: options.wifi_port
|
@@ -107,8 +108,6 @@ When in interactive shell mode:
|
|
107
108
|
end
|
108
109
|
|
109
110
|
|
110
|
-
# Until command line option parsing is added, the only way to specify
|
111
|
-
# verbose mode is in the environment variable MAC_WIFI_OPTS.
|
112
111
|
def verbose_mode
|
113
112
|
options.verbose
|
114
113
|
end
|
@@ -177,9 +176,9 @@ When in interactive shell mode:
|
|
177
176
|
begin
|
178
177
|
require 'pry'
|
179
178
|
rescue LoadError
|
180
|
-
|
181
|
-
|
182
|
-
|
179
|
+
message = "The 'pry' gem and/or one of its prerequisites, required for running the shell, was not found." +
|
180
|
+
" Please `gem install pry` or, if necessary, `sudo gem install pry`."
|
181
|
+
raise Error.new(message)
|
183
182
|
end
|
184
183
|
|
185
184
|
print_help
|
@@ -197,13 +196,25 @@ When in interactive shell mode:
|
|
197
196
|
end
|
198
197
|
|
199
198
|
|
200
|
-
#
|
201
|
-
def
|
202
|
-
|
203
|
-
|
204
|
-
|
199
|
+
# Look up the command name and, if found, run it. If not, execute the passed block.
|
200
|
+
def attempt_command_action(command, *args, &error_handler_block)
|
201
|
+
action = find_command_action(command)
|
202
|
+
|
203
|
+
if action
|
204
|
+
action.(*args)
|
205
205
|
else
|
206
|
-
|
206
|
+
error_handler_block.call
|
207
|
+
nil
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
# For use by the shell when the user types the DSL commands
|
213
|
+
def method_missing(method_name, *method_args)
|
214
|
+
attempt_command_action(method_name.to_s, *method_args) do
|
215
|
+
puts(%Q{"#{method_name}" is not a valid command or option. } \
|
216
|
+
<< 'If you intend for this to be a string literal, ' \
|
217
|
+
<< 'use quotes or %q{}/%Q{}.')
|
207
218
|
end
|
208
219
|
end
|
209
220
|
|
@@ -214,18 +225,16 @@ When in interactive shell mode:
|
|
214
225
|
# be in a form that the Ruby interpreter will recognize as a string,
|
215
226
|
# i.e. single or double quotes, %q, %Q, etc.
|
216
227
|
# Otherwise it will assume it's a method name and pass it to method_missing!
|
217
|
-
def process_command_line
|
218
|
-
|
219
|
-
if action
|
220
|
-
action.(*args)
|
221
|
-
else
|
228
|
+
def process_command_line
|
229
|
+
attempt_command_action(ARGV[0], *ARGV[1..-1]) do
|
222
230
|
print_help
|
223
231
|
raise BadCommandError.new(
|
224
|
-
%Q{Unrecognized command. Command was "#{
|
232
|
+
%Q{! Unrecognized command. Command was "#{ARGV.first.inspect}" and options were #{ARGV[1..-1].inspect}.})
|
225
233
|
end
|
226
234
|
end
|
227
235
|
|
228
236
|
|
237
|
+
|
229
238
|
def quit
|
230
239
|
if interactive_mode
|
231
240
|
exit(0)
|
@@ -313,7 +322,6 @@ When in interactive shell mode:
|
|
313
322
|
# Performs nameserver functionality.
|
314
323
|
# @param subcommand 'get' or no arg to get, 'clear' to clear, and an array of IP addresses to set
|
315
324
|
def cmd_na(*args)
|
316
|
-
|
317
325
|
subcommand = if [[], ['get']].include?(args)
|
318
326
|
:get
|
319
327
|
elsif args == ['clear']
|
@@ -473,7 +481,6 @@ When in interactive shell mode:
|
|
473
481
|
&& \
|
474
482
|
command_string.length >= cmd.min_string.length # e.g. 'c' by itself should not work
|
475
483
|
end
|
476
|
-
|
477
484
|
result ? result.action : nil
|
478
485
|
end
|
479
486
|
|
@@ -494,7 +501,7 @@ When in interactive shell mode:
|
|
494
501
|
begin
|
495
502
|
# By this time, the Main class has removed the command line options, and all that is left
|
496
503
|
# in ARGV is the commands and their options.
|
497
|
-
process_command_line
|
504
|
+
process_command_line
|
498
505
|
rescue BadCommandError => error
|
499
506
|
separator_line = "! #{'-' * 75} !\n"
|
500
507
|
puts '' << separator_line << error.to_s << "\n" << separator_line
|
data/lib/wifi-wand/main.rb
CHANGED
@@ -37,8 +37,10 @@ class Main
|
|
37
37
|
choice = v[0].downcase
|
38
38
|
|
39
39
|
unless formatters.keys.include?(choice)
|
40
|
-
|
41
|
-
|
40
|
+
message = %Q{Output format "#{choice}" not in list of available formats} <<
|
41
|
+
" (#{formatters.keys})."
|
42
|
+
puts; puts message; puts
|
43
|
+
raise Error.new(message)
|
42
44
|
end
|
43
45
|
|
44
46
|
options.post_processor = formatters[choice]
|
@@ -2,6 +2,8 @@ require 'json'
|
|
2
2
|
require 'net/http'
|
3
3
|
require 'tempfile'
|
4
4
|
require 'uri'
|
5
|
+
require_relative 'helpers/command_output_formatter'
|
6
|
+
require_relative '../error'
|
5
7
|
require_relative '../../wifi-wand'
|
6
8
|
|
7
9
|
module WifiWand
|
@@ -33,30 +35,18 @@ class BaseModel
|
|
33
35
|
@verbose_mode = options.verbose
|
34
36
|
|
35
37
|
if options.wifi_port && (! is_wifi_port?(options.wifi_port))
|
36
|
-
raise "#{options.wifi_port} is not a Wi-Fi interface."
|
38
|
+
raise Error.new("#{options.wifi_port} is not a Wi-Fi interface.")
|
37
39
|
end
|
38
40
|
@wifi_port = options.wifi_port
|
39
41
|
end
|
40
42
|
|
41
43
|
|
42
|
-
def banner_line
|
43
|
-
@banner_line ||= '-' * 79
|
44
|
-
end
|
45
|
-
|
46
|
-
def command_attempt_as_string(command)
|
47
|
-
"\n\n#{banner_line}\nCommand: #{command}\n"
|
48
|
-
end
|
49
|
-
|
50
|
-
def command_result_as_string(output)
|
51
|
-
"#{output}#{banner_line}\n\n"
|
52
|
-
end
|
53
|
-
|
54
44
|
|
55
45
|
|
56
46
|
def run_os_command(command, raise_on_error = true)
|
57
47
|
|
58
48
|
if @verbose_mode
|
59
|
-
puts command_attempt_as_string(command)
|
49
|
+
puts CommandOutputFormatter.command_attempt_as_string(command)
|
60
50
|
end
|
61
51
|
|
62
52
|
start_time = Time.now
|
@@ -64,7 +54,7 @@ class BaseModel
|
|
64
54
|
|
65
55
|
if @verbose_mode
|
66
56
|
puts "Duration: #{'%.4f' % [Time.now - start_time]} seconds"
|
67
|
-
puts command_result_as_string(output)
|
57
|
+
puts CommandOutputFormatter.command_result_as_string(output)
|
68
58
|
end
|
69
59
|
|
70
60
|
if $?.exitstatus != 0 && raise_on_error
|
@@ -94,7 +84,7 @@ class BaseModel
|
|
94
84
|
success = true
|
95
85
|
|
96
86
|
if @verbose_mode
|
97
|
-
puts command_attempt_as_string("[Calling Net:HTTP.start(#{url.host})]")
|
87
|
+
puts CommandOutputFormatter.command_attempt_as_string("[Calling Net:HTTP.start(#{url.host})]")
|
98
88
|
end
|
99
89
|
|
100
90
|
start_time = Time.now
|
@@ -110,7 +100,7 @@ class BaseModel
|
|
110
100
|
|
111
101
|
if @verbose_mode
|
112
102
|
puts "Duration: #{'%.4f' % [Time.now - start_time]} seconds"
|
113
|
-
puts command_result_as_string("#{success}\n")
|
103
|
+
puts CommandOutputFormatter.command_result_as_string("#{success}\n")
|
114
104
|
end
|
115
105
|
|
116
106
|
success
|
@@ -146,7 +136,7 @@ class BaseModel
|
|
146
136
|
password = password.to_s if password
|
147
137
|
|
148
138
|
if network_name.nil? || network_name.empty?
|
149
|
-
raise "A network name is required but was not provided."
|
139
|
+
raise Error.new("A network name is required but was not provided.")
|
150
140
|
end
|
151
141
|
wifi_on
|
152
142
|
os_level_connect(network_name, password)
|
@@ -161,7 +151,7 @@ class BaseModel
|
|
161
151
|
message << %Q{connected to "#{connected_network_name}" instead.}
|
162
152
|
end
|
163
153
|
message << ' Did you ' << (password ? "provide the correct password?" : "need to provide a password?")
|
164
|
-
raise message
|
154
|
+
raise Error.new(message)
|
165
155
|
end
|
166
156
|
nil
|
167
157
|
end
|
@@ -181,7 +171,7 @@ class BaseModel
|
|
181
171
|
if preferred_networks.include?(preferred_network_name)
|
182
172
|
os_level_preferred_network_password(preferred_network_name)
|
183
173
|
else
|
184
|
-
raise "Network #{preferred_network_name} not in preferred networks list."
|
174
|
+
raise Error.new("Network #{preferred_network_name} not in preferred networks list.")
|
185
175
|
end
|
186
176
|
end
|
187
177
|
|
@@ -225,12 +215,20 @@ class BaseModel
|
|
225
215
|
# @stop_condition a lambda taking the command's stdout as its sole parameter
|
226
216
|
# @return the stdout produced by the command
|
227
217
|
def try_os_command_until(command, stop_condition, max_tries = 100)
|
228
|
-
|
218
|
+
|
219
|
+
report_attempt_count = ->(attempt_count) do
|
220
|
+
puts "Command was executed #{attempt_count} time(s)." if @verbose_mode
|
221
|
+
end
|
222
|
+
|
223
|
+
max_tries.times do |n|
|
229
224
|
stdout = run_os_command(command)
|
230
225
|
if stop_condition.(stdout)
|
226
|
+
report_attempt_count.(n + 1)
|
231
227
|
return stdout
|
232
228
|
end
|
233
229
|
end
|
230
|
+
|
231
|
+
report_attempt_count.(max_tries)
|
234
232
|
nil
|
235
233
|
end
|
236
234
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module WifiWand
|
2
|
+
module CommandOutputFormatter
|
3
|
+
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def banner_line
|
7
|
+
@banner_line ||= '-' * 79
|
8
|
+
end
|
9
|
+
|
10
|
+
def command_attempt_as_string(command)
|
11
|
+
"\n\n#{banner_line}\nCommand: #{command}\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
def command_result_as_string(output)
|
15
|
+
"#{output}#{banner_line}\n\n"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'ipaddr'
|
2
2
|
require 'ostruct'
|
3
|
+
require 'rexml/document'
|
3
4
|
require 'shellwords'
|
4
5
|
|
5
6
|
require_relative 'base_model'
|
7
|
+
require_relative '../error'
|
6
8
|
|
7
9
|
module WifiWand
|
8
10
|
|
@@ -16,6 +18,21 @@ class MacOsModel < BaseModel
|
|
16
18
|
end
|
17
19
|
|
18
20
|
|
21
|
+
# Although at this time the airport command utility is predictable,
|
22
|
+
# allow putting it elsewhere in the path for overriding and easier fix
|
23
|
+
# if that location should change.
|
24
|
+
def airport_command
|
25
|
+
airport_in_path = `which airport`.chomp
|
26
|
+
if ! airport_in_path.empty?
|
27
|
+
airport_in_path
|
28
|
+
elsif File.exist?(AIRPORT_CMD)
|
29
|
+
AIRPORT_CMD
|
30
|
+
else
|
31
|
+
raise Error.new("Airport command not found.")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
19
36
|
# Identifies the (first) wireless network hardware port in the system, e.g. en0 or en1
|
20
37
|
# This may not detect wifi ports with nonstandard names, such as USB wifi devices.
|
21
38
|
def detect_wifi_port
|
@@ -35,7 +52,7 @@ class MacOsModel < BaseModel
|
|
35
52
|
end
|
36
53
|
|
37
54
|
if wifi_port_line_num.nil?
|
38
|
-
raise %Q{Wifi port (e.g. "en0") not found in output of: networksetup -listallhardwareports}
|
55
|
+
raise Error.new(%Q{Wifi port (e.g. "en0") not found in output of: networksetup -listallhardwareports})
|
39
56
|
else
|
40
57
|
lines[wifi_port_line_num + 1].split(': ').last
|
41
58
|
end
|
@@ -56,7 +73,7 @@ class MacOsModel < BaseModel
|
|
56
73
|
# "DIRECT-sq-BRAVIA 02:71:cc:87:4a:8c -76 6 Y -- WPA2(PSK/AES/AES) ", #
|
57
74
|
def available_network_info
|
58
75
|
return nil unless wifi_on? # no need to try
|
59
|
-
command = "#{
|
76
|
+
command = "#{airport_command} -s"
|
60
77
|
max_attempts = 50
|
61
78
|
|
62
79
|
|
@@ -87,27 +104,59 @@ class MacOsModel < BaseModel
|
|
87
104
|
if output
|
88
105
|
process_tabular_data.(output)
|
89
106
|
else
|
90
|
-
raise "Unable to get available network information after #{max_attempts} attempts."
|
107
|
+
raise Error.new("Unable to get available network information after #{max_attempts} attempts.")
|
91
108
|
end
|
92
109
|
end
|
93
110
|
|
94
111
|
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
112
|
+
# The Mac OS airport utility (at
|
113
|
+
# /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport)
|
114
|
+
# outputs the network names right padded with spaces so there is no way to differentiate a
|
115
|
+
# network name *with* leading space(s) from one without:
|
116
|
+
#
|
117
|
+
# SSID BSSID RSSI CHANNEL HT CC SECURITY (auth/unicast/group)
|
118
|
+
# ngHub_319442NL0293C 04:a1:51:58:5b:05 -65 11 Y US WPA2(PSK/AES/AES)
|
119
|
+
# NETGEAR89_2GEXT 9c:3d:cf:11:69:b4 -67 8 Y US NONE
|
120
|
+
#
|
121
|
+
# To remedy this, they offer a "-x" option that outputs the information in (pseudo) XML.
|
122
|
+
# This XML has 'dict' elements that contain many elements. The SSID can be found in the
|
123
|
+
# XML element <string> which immediately follows an XML element whose text is "SSID_STR".
|
124
|
+
# Unfortunately, since there is no way to connect the two other than their physical location,
|
125
|
+
# the key is rather useless for XML parsing.
|
126
|
+
#
|
127
|
+
# I tried extracting the arrays of keys and strings, and finding the string element
|
128
|
+
# at the same position in the string array as the 'SSID_STR' was in the keys array.
|
129
|
+
# However, not all keys had string elements, so the index in the key array was the wrong index.
|
130
|
+
# Here is an excerpt from the XML output:
|
131
|
+
#
|
132
|
+
# <key>RSSI</key>
|
133
|
+
# <integer>-91</integer>
|
134
|
+
# <key>SSID</key>
|
135
|
+
# <data>
|
136
|
+
# TkVUR0VBUjY1
|
137
|
+
# </data>
|
138
|
+
# <key>SSID_STR</key>
|
139
|
+
# <string>NETGEAR65</string>
|
140
|
+
#
|
141
|
+
# The kludge I came up with was that the ssid was always the 2nd value in the <string> element
|
142
|
+
# array, so that's what is used here.
|
143
|
+
#
|
144
|
+
# But now even that approach has been superseded by the XPath approach now used.
|
145
|
+
#
|
146
|
+
# REXML is used here to avoid the need for the user to install Nokogiri.
|
98
147
|
def available_network_names
|
148
|
+
# For some reason, the airport command very often returns nothing, so we need to try until
|
149
|
+
# we get data in the response:
|
99
150
|
|
100
|
-
|
101
|
-
command = %Q{#{AIRPORT_CMD} -s -x | awk '{ if (catch == 1) { print; catch=0 } } /SSID_STR/ { catch=1 }'}
|
151
|
+
command = "#{airport_command} -s -x"
|
102
152
|
stop_condition = ->(response) { ! [nil, ''].include?(response) }
|
103
|
-
|
104
153
|
output = try_os_command_until(command, stop_condition)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
154
|
+
doc = REXML::Document.new(output)
|
155
|
+
xpath = '//key[text() = "SSID_STR"][1]/following-sibling::*[1]' # provided by @ScreenStaring on Twitter
|
156
|
+
REXML::XPath.match(doc, xpath) \
|
157
|
+
.map(&:text) \
|
158
|
+
.sort { |x,y| x.casecmp(y) } \
|
159
|
+
.uniq
|
111
160
|
end
|
112
161
|
|
113
162
|
|
@@ -136,7 +185,7 @@ class MacOsModel < BaseModel
|
|
136
185
|
|
137
186
|
# Returns true if wifi is on, else false.
|
138
187
|
def wifi_on?
|
139
|
-
lines = run_os_command("#{
|
188
|
+
lines = run_os_command("#{airport_command} -I").split("\n")
|
140
189
|
lines.grep("AirPort: Off").none?
|
141
190
|
end
|
142
191
|
|
@@ -145,7 +194,7 @@ class MacOsModel < BaseModel
|
|
145
194
|
def wifi_on
|
146
195
|
return if wifi_on?
|
147
196
|
run_os_command("networksetup -setairportpower #{wifi_port} on")
|
148
|
-
wifi_on? ? nil : raise("Wifi could not be enabled.")
|
197
|
+
wifi_on? ? nil : Error.new(raise("Wifi could not be enabled."))
|
149
198
|
end
|
150
199
|
|
151
200
|
|
@@ -153,7 +202,7 @@ class MacOsModel < BaseModel
|
|
153
202
|
def wifi_off
|
154
203
|
return unless wifi_on?
|
155
204
|
run_os_command("networksetup -setairportpower #{wifi_port} off")
|
156
|
-
wifi_on? ? raise("Wifi could not be disabled.") : nil
|
205
|
+
wifi_on? ? Error.new(raise("Wifi could not be disabled.")) : nil
|
157
206
|
end
|
158
207
|
|
159
208
|
|
@@ -210,7 +259,7 @@ class MacOsModel < BaseModel
|
|
210
259
|
|
211
260
|
# Returns the network currently connected to, or nil if none.
|
212
261
|
def connected_network_name
|
213
|
-
lines = run_os_command("#{
|
262
|
+
lines = run_os_command("#{airport_command} -I").split("\n")
|
214
263
|
ssid_lines = lines.grep(/ SSID:/)
|
215
264
|
ssid_lines.empty? ? nil : ssid_lines.first.split('SSID: ').last.lstrip
|
216
265
|
end
|
@@ -218,7 +267,7 @@ class MacOsModel < BaseModel
|
|
218
267
|
|
219
268
|
# Disconnects from the currently connected network. Does not turn off wifi.
|
220
269
|
def disconnect
|
221
|
-
run_os_command("sudo #{
|
270
|
+
run_os_command("sudo #{airport_command} -z")
|
222
271
|
nil
|
223
272
|
end
|
224
273
|
|
@@ -253,7 +302,7 @@ class MacOsModel < BaseModel
|
|
253
302
|
'nameservers' => nameservers_using_scutil,
|
254
303
|
'timestamp' => Time.now,
|
255
304
|
}
|
256
|
-
more_output = run_os_command(
|
305
|
+
more_output = run_os_command(airport_command + " -I")
|
257
306
|
more_info = colon_output_to_hash(more_output)
|
258
307
|
info.merge!(more_info)
|
259
308
|
info.delete('AirPort') # will be here if off, but info is already in wifi_on key
|
@@ -285,11 +334,12 @@ class MacOsModel < BaseModel
|
|
285
334
|
end
|
286
335
|
|
287
336
|
unless bad_addresses.empty?
|
288
|
-
raise "Bad IP addresses provided: #{bad_addresses.join(', ')}"
|
337
|
+
raise Error.new("Bad IP addresses provided: #{bad_addresses.join(', ')}")
|
289
338
|
end
|
290
339
|
nameservers.join(' ')
|
291
340
|
end
|
292
341
|
run_os_command("networksetup -setdnsservers Wi-Fi #{arg}")
|
342
|
+
nameservers
|
293
343
|
end
|
294
344
|
|
295
345
|
|
@@ -313,6 +363,7 @@ class MacOsModel < BaseModel
|
|
313
363
|
end
|
314
364
|
private :colon_output_to_hash
|
315
365
|
|
366
|
+
|
316
367
|
# @return array of nameserver IP addresses from /etc/resolv.conf, or nil if not found
|
317
368
|
# Though this is strictly *not* OS-agnostic, it will be used by most OS's,
|
318
369
|
# and can be overridden by subclasses (e.g. Windows).
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module WifiWand
|
2
|
+
|
3
|
+
class ModelValidator
|
4
|
+
|
5
|
+
BASE_MODEL_ESSENTIAL_METHODS = [
|
6
|
+
:connect,
|
7
|
+
:connected_to?,
|
8
|
+
:connected_to_internet?,
|
9
|
+
:cycle_network,
|
10
|
+
:preferred_network_password,
|
11
|
+
:public_ip_address_info,
|
12
|
+
:random_mac_address,
|
13
|
+
:remove_preferred_networks,
|
14
|
+
:run_os_command,
|
15
|
+
:till,
|
16
|
+
:try_os_command_until,
|
17
|
+
:verbose_mode,
|
18
|
+
:verbose_mode=,
|
19
|
+
:wifi_port,
|
20
|
+
:wifi_port=
|
21
|
+
]
|
22
|
+
|
23
|
+
|
24
|
+
BASE_MODEL_NONESSENTIAL_METHODS = [
|
25
|
+
]
|
26
|
+
|
27
|
+
|
28
|
+
MAC_OS_MODEL_ESSENTIAL_METHODS = [
|
29
|
+
:airport_command,
|
30
|
+
:available_network_info,
|
31
|
+
:available_network_names,
|
32
|
+
:connected_network_name,
|
33
|
+
:detect_wifi_port,
|
34
|
+
:disconnect,
|
35
|
+
:ip_address,
|
36
|
+
:is_wifi_port?,
|
37
|
+
:mac_address,
|
38
|
+
:nameservers_using_networksetup,
|
39
|
+
:nameservers_using_resolv_conf,
|
40
|
+
:nameservers_using_scutil,
|
41
|
+
:open_resource,
|
42
|
+
:os_level_connect,
|
43
|
+
:os_level_preferred_network_password,
|
44
|
+
:preferred_networks,
|
45
|
+
:remove_preferred_network,
|
46
|
+
:set_nameservers,
|
47
|
+
:wifi_info,
|
48
|
+
:wifi_off,
|
49
|
+
:wifi_on,
|
50
|
+
:wifi_on?
|
51
|
+
]
|
52
|
+
|
53
|
+
MAC_OS_MODEL_ESSENTIAL_METHODS = [
|
54
|
+
]
|
55
|
+
|
56
|
+
ALL_MODEL_METHODS = BASE_MODEL_ESSENTIAL_METHODS + MAC_OS_MODEL_ESSENTIAL_METHODS
|
57
|
+
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative 'error'
|
1
2
|
require_relative 'os/base_os'
|
2
3
|
require_relative 'os/imaginary_os'
|
3
4
|
require_relative 'os/mac_os'
|
@@ -31,7 +32,7 @@ class OperatingSystems
|
|
31
32
|
matches = supported_operating_systems.select { |os| os.current_os_is_this_os? }
|
32
33
|
if matches.size > 1
|
33
34
|
matching_names = matches.map(&:display_name)
|
34
|
-
raise "There should only be 1 matching OS, but there were multiple: #{matching_names.inspect}"
|
35
|
+
raise Error.new("There should only be 1 matching OS, but there were multiple: #{matching_names.inspect}")
|
35
36
|
end
|
36
37
|
@current_os = matches.first
|
37
38
|
end
|
@@ -39,8 +40,8 @@ class OperatingSystems
|
|
39
40
|
end
|
40
41
|
|
41
42
|
|
42
|
-
def current_id; current_os
|
43
|
-
def current_display_name; current_os
|
43
|
+
def current_id; current_os ? current_os.id : nil; end
|
44
|
+
def current_display_name; current_os ? current_os.display_name : nil; end
|
44
45
|
|
45
46
|
end
|
46
47
|
end
|
data/lib/wifi-wand/version.rb
CHANGED
data/wifi-wand.gemspec
CHANGED
@@ -7,8 +7,8 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.version = WifiWand::VERSION
|
8
8
|
spec.authors = ["Keith Bennett"]
|
9
9
|
spec.email = ["keithrbennett@gmail.com"]
|
10
|
-
spec.description = %q{A command line interface for managing
|
11
|
-
spec.summary = %q{Mac
|
10
|
+
spec.description = %q{A command line interface for managing WiFi on a Mac.}
|
11
|
+
spec.summary = %q{Mac WiFi utility}
|
12
12
|
spec.homepage = "https://github.com/keithrbennett/wifi-wand"
|
13
13
|
spec.license = "MIT"
|
14
14
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wifi-wand
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Bennett
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,7 +52,7 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
|
-
description: A command line interface for managing
|
55
|
+
description: A command line interface for managing WiFi on a Mac.
|
56
56
|
email:
|
57
57
|
- keithrbennett@gmail.com
|
58
58
|
executables:
|
@@ -68,9 +68,12 @@ files:
|
|
68
68
|
- exe/wifi-wand
|
69
69
|
- lib/wifi-wand.rb
|
70
70
|
- lib/wifi-wand/command_line_interface.rb
|
71
|
+
- lib/wifi-wand/error.rb
|
71
72
|
- lib/wifi-wand/main.rb
|
72
73
|
- lib/wifi-wand/models/base_model.rb
|
74
|
+
- lib/wifi-wand/models/helpers/command_output_formatter.rb
|
73
75
|
- lib/wifi-wand/models/mac_os_model.rb
|
76
|
+
- lib/wifi-wand/models/model_validator.rb
|
74
77
|
- lib/wifi-wand/operating_systems.rb
|
75
78
|
- lib/wifi-wand/os/base_os.rb
|
76
79
|
- lib/wifi-wand/os/imaginary_os.rb
|
@@ -105,5 +108,5 @@ rubyforge_project:
|
|
105
108
|
rubygems_version: 2.7.6
|
106
109
|
signing_key:
|
107
110
|
specification_version: 4
|
108
|
-
summary: Mac
|
111
|
+
summary: Mac WiFi utility
|
109
112
|
test_files: []
|