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 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