wifi-wand 2.17.1 → 2.19.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 +10 -0
- data/lib/wifi-wand/models/base_model.rb +19 -32
- data/lib/wifi-wand/models/mac_os_model.rb +22 -14
- data/lib/wifi-wand/version.rb +1 -1
- data/swift/WifiNetworkConnecter.swift +57 -0
- data/swift/WifiNetworkDisconecter.swift +1 -1
- data/wifi-wand.gemspec +3 -0
- metadata +23 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3d9a52dffd83c2be845f91172481ee2df4c140d188c3374573f9c76cb43d199
|
4
|
+
data.tar.gz: 2962e28498baa51617b5ec42b65304065c1e4aaafd109f2de3e3da1ba8ffde30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23a13c3964972c417dd20131718cb5614ad5a1bfccdd30ee2a52173fd0761ebe40981bd4b11e6c8808dfb3aaefc0a0178ccd8fad8d247fd6413776676af5bf3e
|
7
|
+
data.tar.gz: 603dbd8e5eb821df3b42112eac3c5ba92b92e953a2913a56b813190491a69b8a4a91172a2963b05f350bf65340bd007332f63e0e94601130862316970cfafeef
|
data/RELEASE_NOTES.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## v2.19.0
|
2
|
+
|
3
|
+
* Replace `networksetup` with Swift script for connecting to a network.
|
4
|
+
* For getting connected network name, replace `networksetup` with `ipconfig`.
|
5
|
+
|
6
|
+
## v2.18.0
|
7
|
+
|
8
|
+
* Remove 'hotspot_login_required' informational item and logic (was not working correctly).
|
9
|
+
|
10
|
+
|
1
11
|
## v2.17.1
|
2
12
|
|
3
13
|
* Fix verbose output for running a Swift command.
|
@@ -11,25 +11,6 @@ class BaseModel
|
|
11
11
|
|
12
12
|
attr_accessor :wifi_interface, :verbose_mode
|
13
13
|
|
14
|
-
class OsCommandError < RuntimeError
|
15
|
-
attr_reader :exitstatus, :command, :text
|
16
|
-
|
17
|
-
def initialize(exitstatus, command, text)
|
18
|
-
@exitstatus = exitstatus
|
19
|
-
@command = command
|
20
|
-
@text = text
|
21
|
-
end
|
22
|
-
|
23
|
-
def to_s
|
24
|
-
"#{self.class.name}: Error code #{exitstatus}, command = #{command}, text = #{text}"
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_h
|
28
|
-
{ exitstatus: exitstatus, command: command, text: text }
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
14
|
def initialize(options)
|
34
15
|
@verbose_mode = options.verbose
|
35
16
|
|
@@ -130,13 +111,6 @@ class BaseModel
|
|
130
111
|
end
|
131
112
|
|
132
113
|
|
133
|
-
def hotspot_login_required
|
134
|
-
response_text = run_os_command('curl --max-time 3 http://captive.apple.com', false)
|
135
|
-
required = ['Error', '302', 'Hotspot login required'].all? { |s| response_text.include?(s) }
|
136
|
-
required
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
114
|
# Turns wifi off and then on, reconnecting to the originally connecting network.
|
141
115
|
def cycle_network
|
142
116
|
# TODO: Make this network name saving and restoring conditional on it not having a password.
|
@@ -171,12 +145,7 @@ class BaseModel
|
|
171
145
|
# Verify that the network is now connected:
|
172
146
|
actual_network_name = connected_network_name
|
173
147
|
|
174
|
-
|
175
|
-
if hotspot_login_required
|
176
|
-
puts "Hotspot login required. Opening browser to captive.apple.com."
|
177
|
-
`open https://captive.apple.com`
|
178
|
-
end
|
179
|
-
else
|
148
|
+
unless actual_network_name == network_name
|
180
149
|
message = %Q{Expected to connect to "#{network_name}" but }
|
181
150
|
if actual_network_name.nil? || actual_network_name.empty?
|
182
151
|
message << "unable to connect to any network."
|
@@ -286,5 +255,23 @@ class BaseModel
|
|
286
255
|
def wifi_interface
|
287
256
|
@wifi_interface ||= detect_wifi_interface
|
288
257
|
end
|
258
|
+
|
259
|
+
class OsCommandError < RuntimeError
|
260
|
+
attr_reader :exitstatus, :command, :text
|
261
|
+
|
262
|
+
def initialize(exitstatus, command, text)
|
263
|
+
@exitstatus = exitstatus
|
264
|
+
@command = command
|
265
|
+
@text = text
|
266
|
+
end
|
267
|
+
|
268
|
+
def to_s
|
269
|
+
"#{self.class.name}: Error code #{exitstatus}, command = #{command}, text = #{text}"
|
270
|
+
end
|
271
|
+
|
272
|
+
def to_h
|
273
|
+
{ exitstatus: exitstatus, command: command, text: text }
|
274
|
+
end
|
275
|
+
end
|
289
276
|
end
|
290
277
|
end
|
@@ -96,7 +96,7 @@ class MacOsModel < BaseModel
|
|
96
96
|
|
97
97
|
|
98
98
|
# This method is called by BaseModel#connect to do the OS-specific connection logic.
|
99
|
-
def
|
99
|
+
def os_level_connect_using_networksetup(network_name, password = nil)
|
100
100
|
command = "networksetup -setairportnetwork #{wifi_interface} #{Shellwords.shellescape(network_name)}"
|
101
101
|
if password
|
102
102
|
command << ' ' << Shellwords.shellescape(password)
|
@@ -104,6 +104,17 @@ class MacOsModel < BaseModel
|
|
104
104
|
run_os_command(command)
|
105
105
|
end
|
106
106
|
|
107
|
+
def os_level_connect_using_swift(network_name, password = nil)
|
108
|
+
ensure_swift_and_corewlan_present
|
109
|
+
args = [Shellwords.shellescape(network_name)]
|
110
|
+
args << Shellwords.shellescape(password) if password
|
111
|
+
run_swift_command('WifiNetworkConnecter', *args)
|
112
|
+
end
|
113
|
+
|
114
|
+
def os_level_connect(network_name, password = nil)
|
115
|
+
os_level_connect_using_swift(network_name, password)
|
116
|
+
end
|
117
|
+
|
107
118
|
|
108
119
|
# @return:
|
109
120
|
# If the network is in the preferred networks list
|
@@ -151,10 +162,10 @@ class MacOsModel < BaseModel
|
|
151
162
|
def connected_network_name
|
152
163
|
return nil unless wifi_on? # no need to try
|
153
164
|
|
154
|
-
command_output = run_os_command("
|
155
|
-
|
156
|
-
|
157
|
-
|
165
|
+
command_output = run_os_command("ipconfig getsummary #{wifi_interface} | grep ' SSID :'", false)
|
166
|
+
return nil if command_output.nil?
|
167
|
+
|
168
|
+
command_output.split('SSID :').last.strip
|
158
169
|
end
|
159
170
|
|
160
171
|
|
@@ -187,12 +198,9 @@ class MacOsModel < BaseModel
|
|
187
198
|
false
|
188
199
|
end
|
189
200
|
|
190
|
-
need_hotspot_login = hotspot_login_required
|
191
|
-
|
192
201
|
info = {
|
193
202
|
'wifi_on' => wifi_on?,
|
194
203
|
'internet_on' => connected,
|
195
|
-
'hotspot_login_required' => need_hotspot_login,
|
196
204
|
'interface' => wifi_interface,
|
197
205
|
'network' => connected_network_name,
|
198
206
|
'ip_address' => ip_address,
|
@@ -201,7 +209,7 @@ class MacOsModel < BaseModel
|
|
201
209
|
'timestamp' => Time.now,
|
202
210
|
}
|
203
211
|
|
204
|
-
if info['internet_on']
|
212
|
+
if info['internet_on']
|
205
213
|
begin
|
206
214
|
info['public_ip'] = public_ip_address_info
|
207
215
|
rescue => e
|
@@ -309,12 +317,12 @@ class MacOsModel < BaseModel
|
|
309
317
|
system("swift -e 'import CoreWLAN' >/dev/null 2>&1")
|
310
318
|
end
|
311
319
|
|
312
|
-
|
320
|
+
|
321
|
+
def run_swift_command(basename, *args)
|
313
322
|
ensure_swift_and_corewlan_present
|
314
|
-
swift_filespec = File.join(
|
315
|
-
|
316
|
-
)
|
317
|
-
command = "swift #{swift_filespec}"
|
323
|
+
swift_filespec = File.absolute_path(File.join(File.dirname(__FILE__), "../../../swift/#{basename}.swift"))
|
324
|
+
argv = ['swift', swift_filespec] + args
|
325
|
+
command = argv.compact.join(' ')
|
318
326
|
run_os_command(command)
|
319
327
|
end
|
320
328
|
end
|
data/lib/wifi-wand/version.rb
CHANGED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env swift
|
2
|
+
|
3
|
+
import Foundation
|
4
|
+
import CoreWLAN
|
5
|
+
|
6
|
+
// Function to connect to a network
|
7
|
+
func connectToNetwork(ssid: String, password: String?) -> Bool {
|
8
|
+
guard let interface = CWWiFiClient.shared().interface() else {
|
9
|
+
print("Error: Could not get WiFi interface")
|
10
|
+
exit(1)
|
11
|
+
}
|
12
|
+
|
13
|
+
do {
|
14
|
+
// Scan for networks
|
15
|
+
let networks = try interface.scanForNetworks(withSSID: ssid.data(using: .utf8))
|
16
|
+
guard let network = networks.first else {
|
17
|
+
print("Error: Network not found")
|
18
|
+
exit(1)
|
19
|
+
}
|
20
|
+
|
21
|
+
// Connect to the network
|
22
|
+
try interface.associate(to: network, password: password)
|
23
|
+
return true
|
24
|
+
} catch let error as NSError {
|
25
|
+
// Handle specific error cases
|
26
|
+
switch error.code {
|
27
|
+
case -3931: // Already connected
|
28
|
+
print("Already connected to network")
|
29
|
+
return true
|
30
|
+
case -3906: // Invalid password
|
31
|
+
print("Error: Invalid password")
|
32
|
+
case -3905: // Network not found
|
33
|
+
print("Error: Network not found")
|
34
|
+
case -3908: // Timeout
|
35
|
+
print("Error: Connection timeout")
|
36
|
+
case -3903: // Authentication failed
|
37
|
+
print("Error: Authentication failed - might require captive portal login")
|
38
|
+
default:
|
39
|
+
print("Error connecting: \(error.localizedDescription) (code: \(error.code))")
|
40
|
+
}
|
41
|
+
exit(1)
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
// Parse command line arguments
|
46
|
+
if CommandLine.arguments.count < 2 {
|
47
|
+
print("Usage: \(CommandLine.arguments[0]) SSID [password]")
|
48
|
+
exit(1)
|
49
|
+
}
|
50
|
+
|
51
|
+
let ssid = CommandLine.arguments[1]
|
52
|
+
let password = CommandLine.arguments.count > 2 ? CommandLine.arguments[2] : nil
|
53
|
+
|
54
|
+
if connectToNetwork(ssid: ssid, password: password) {
|
55
|
+
print("ok")
|
56
|
+
exit(0)
|
57
|
+
}
|
data/wifi-wand.gemspec
CHANGED
@@ -21,6 +21,9 @@ Gem::Specification.new do |spec|
|
|
21
21
|
# spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
22
|
spec.add_dependency('awesome_print', '>= 1.9.2', '< 2')
|
23
23
|
|
24
|
+
# ostruct will no longer be part of the default gems starting from Ruby 3.5.0.
|
25
|
+
spec.add_dependency('ostruct')
|
26
|
+
|
24
27
|
# still on version 0, no need to exclude future versions, but need bug fix for pry not pry'ing
|
25
28
|
# on last line of method:
|
26
29
|
spec.add_dependency('pry', '>= 0.14.2')
|
metadata
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wifi-wand
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.19.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: 2024-
|
11
|
+
date: 2024-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
+
name: awesome_print
|
14
15
|
requirement: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
17
|
- - ">="
|
@@ -19,7 +20,6 @@ dependencies:
|
|
19
20
|
- - "<"
|
20
21
|
- !ruby/object:Gem::Version
|
21
22
|
version: '2'
|
22
|
-
name: awesome_print
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -31,12 +31,26 @@ dependencies:
|
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '2'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
+
name: ostruct
|
34
35
|
requirement: !ruby/object:Gem::Requirement
|
35
36
|
requirements:
|
36
37
|
- - ">="
|
37
38
|
- !ruby/object:Gem::Version
|
38
|
-
version: 0
|
39
|
+
version: '0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
39
48
|
name: pry
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.14.2
|
40
54
|
type: :runtime
|
41
55
|
prerelease: false
|
42
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -45,12 +59,12 @@ dependencies:
|
|
45
59
|
- !ruby/object:Gem::Version
|
46
60
|
version: 0.14.2
|
47
61
|
- !ruby/object:Gem::Dependency
|
62
|
+
name: bundler
|
48
63
|
requirement: !ruby/object:Gem::Requirement
|
49
64
|
requirements:
|
50
65
|
- - ">="
|
51
66
|
- !ruby/object:Gem::Version
|
52
67
|
version: 2.5.9
|
53
|
-
name: bundler
|
54
68
|
type: :development
|
55
69
|
prerelease: false
|
56
70
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -59,12 +73,12 @@ dependencies:
|
|
59
73
|
- !ruby/object:Gem::Version
|
60
74
|
version: 2.5.9
|
61
75
|
- !ruby/object:Gem::Dependency
|
76
|
+
name: rake
|
62
77
|
requirement: !ruby/object:Gem::Requirement
|
63
78
|
requirements:
|
64
79
|
- - ">="
|
65
80
|
- !ruby/object:Gem::Version
|
66
81
|
version: 13.2.1
|
67
|
-
name: rake
|
68
82
|
type: :development
|
69
83
|
prerelease: false
|
70
84
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -73,6 +87,7 @@ dependencies:
|
|
73
87
|
- !ruby/object:Gem::Version
|
74
88
|
version: 13.2.1
|
75
89
|
- !ruby/object:Gem::Dependency
|
90
|
+
name: rspec
|
76
91
|
requirement: !ruby/object:Gem::Requirement
|
77
92
|
requirements:
|
78
93
|
- - ">="
|
@@ -81,7 +96,6 @@ dependencies:
|
|
81
96
|
- - "<"
|
82
97
|
- !ruby/object:Gem::Version
|
83
98
|
version: '4'
|
84
|
-
name: rspec
|
85
99
|
type: :development
|
86
100
|
prerelease: false
|
87
101
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -135,6 +149,7 @@ files:
|
|
135
149
|
- sample-available-networks.yaml
|
136
150
|
- spec/wifi-wand/models/base_model_spec.rb
|
137
151
|
- swift/AvailableWifiNetworkLister.swift
|
152
|
+
- swift/WifiNetworkConnecter.swift
|
138
153
|
- swift/WifiNetworkDisconecter.swift
|
139
154
|
- test-data/invalid-byte-sequence-network-names.txt
|
140
155
|
- wifi-wand.gemspec
|
@@ -157,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
172
|
- !ruby/object:Gem::Version
|
158
173
|
version: '0'
|
159
174
|
requirements: []
|
160
|
-
rubygems_version: 3.5.
|
175
|
+
rubygems_version: 3.5.23
|
161
176
|
signing_key:
|
162
177
|
specification_version: 4
|
163
178
|
summary: Mac WiFi utility
|