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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d83a3c01e4c458c0aa5d1aca6dbb2973b262988adc0c1c4613b0ec7b7f77961
4
- data.tar.gz: 2a7fb69d769c652a91ac114a618aec32ac40642402e849323d0e784bc2c55699
3
+ metadata.gz: b3d9a52dffd83c2be845f91172481ee2df4c140d188c3374573f9c76cb43d199
4
+ data.tar.gz: 2962e28498baa51617b5ec42b65304065c1e4aaafd109f2de3e3da1ba8ffde30
5
5
  SHA512:
6
- metadata.gz: 85e9a23e55f3457070282a38895923a650bd7a21af55969d53bfe0a9836caa7d4a752b977439234fb5aea5963f3df011793c3c6bca7276e84267b5e224a065b9
7
- data.tar.gz: 4629fe47da129ac640f4ee1a9520cac6a22d55da0ec75c74e3c584b7988e90c9d85c4bf68c85c98174ea6ebf9916d68791fee8639c86aded66a029a172bbf32d
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
- if actual_network_name == network_name
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 os_level_connect(network_name, password = nil)
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("networksetup -getairportnetwork #{wifi_interface}")
155
- connected_prefix = 'Current Wi-Fi Network: '
156
- connected = Regexp.new(connected_prefix).match?(command_output)
157
- connected ? command_output.split(connected_prefix).last.chomp : nil
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'] && (! need_hotspot_login)
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
- def run_swift_command(basename)
320
+
321
+ def run_swift_command(basename, *args)
313
322
  ensure_swift_and_corewlan_present
314
- swift_filespec = File.join(
315
- File.dirname(__FILE__), "../../../swift/#{basename}.swift"
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
@@ -1,3 +1,3 @@
1
1
  module WifiWand
2
- VERSION = '2.17.1' unless defined?(VERSION)
2
+ VERSION = '2.19.0' unless defined?(VERSION)
3
3
  end
@@ -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
+ }
@@ -8,6 +8,6 @@ if let wifiInterface = CWWiFiClient.shared().interface() {
8
8
  print("ok")
9
9
  exit(0)
10
10
  } else {
11
- print("error")
11
+ print("Failed to disconnect. One possible reason: XCode not installed.")
12
12
  exit(1)
13
13
  }
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.17.1
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-04-26 00:00:00.000000000 Z
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.14.2
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.9
175
+ rubygems_version: 3.5.23
161
176
  signing_key:
162
177
  specification_version: 4
163
178
  summary: Mac WiFi utility