wifi-wand 2.17.1 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|