@mentra/glasses-media 3.4.0-dev.973 → 3.4.0-dev.975
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.
- package/ios/CoreKit/Sources/GlassesMediaCore/MacHotspotAssociation.swift +8 -4
- package/ios/CoreKit/Sources/GlassesMediaCore/MacHotspotAuthorization.swift +13 -5
- package/ios/CoreKit/Sources/GlassesMediaCore/MacHotspotAuthorizationFacts.swift +51 -0
- package/ios/GlassesHotspotNetwork.swift +5 -4
- package/package.json +1 -1
|
@@ -17,12 +17,13 @@ final class MacHotspotAssociation {
|
|
|
17
17
|
init(deadline: TimeInterval = ProcessInfo.processInfo.systemUptime + 60,
|
|
18
18
|
now: @escaping () -> TimeInterval = { ProcessInfo.processInfo.systemUptime },
|
|
19
19
|
pause: ((TimeInterval) -> Void)? = nil,
|
|
20
|
-
makeInterface:
|
|
20
|
+
makeInterface: (() throws -> MacWifiInterface)? = nil,
|
|
21
|
+
authorizationFacts: MacHotspotAuthorizationFacts? = nil)
|
|
21
22
|
{
|
|
22
23
|
self.deadline = deadline
|
|
23
24
|
self.now = now
|
|
24
25
|
self.pause = pause
|
|
25
|
-
self.makeInterface = makeInterface
|
|
26
|
+
self.makeInterface = makeInterface ?? { try PublicCoreWlanInterface(authorizationFacts: authorizationFacts) }
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
func associate(ssid: String, password: String) throws -> String {
|
|
@@ -129,9 +130,11 @@ enum MacWifiInvocation {
|
|
|
129
130
|
private final class PublicCoreWlanInterface: MacWifiInterface {
|
|
130
131
|
private let bundle: Bundle
|
|
131
132
|
private let interface: NSObject
|
|
133
|
+
private let authorizationFacts: MacHotspotAuthorizationFacts
|
|
132
134
|
private typealias Disassociate = @convention(c) (AnyObject, Selector) -> Void
|
|
133
135
|
|
|
134
|
-
init() throws {
|
|
136
|
+
init(authorizationFacts: MacHotspotAuthorizationFacts? = nil) throws {
|
|
137
|
+
self.authorizationFacts = authorizationFacts ?? MacHotspotAuthorizationFacts()
|
|
135
138
|
guard let bundle = Bundle(path: "/System/Library/Frameworks/CoreWLAN.framework") else {
|
|
136
139
|
throw LocalMediaError("Mac Wi-Fi framework is unavailable")
|
|
137
140
|
}
|
|
@@ -161,7 +164,8 @@ private final class PublicCoreWlanInterface: MacWifiInterface {
|
|
|
161
164
|
func currentSSID() throws -> String? {
|
|
162
165
|
let authorization = CLLocationManager.authorizationStatus()
|
|
163
166
|
guard MacHotspotAuthorization.isAuthorized(authorization) else {
|
|
164
|
-
throw
|
|
167
|
+
throw authorizationFacts.failure("Location access is required to verify the current Mac Wi-Fi network", raw: authorization.rawValue,
|
|
168
|
+
getter: .staticSSID, foreground: MacHotspotAuthorizationFacts.foreground())
|
|
165
169
|
}
|
|
166
170
|
guard let data = interface.perform(NSSelectorFromString("ssidData"))?.takeUnretainedValue() as? Data else { return nil }
|
|
167
171
|
return String(data: data, encoding: .utf8)
|
|
@@ -7,6 +7,12 @@ final class MacHotspotAuthorization: NSObject, CLLocationManagerDelegate {
|
|
|
7
7
|
private var manager: CLLocationManager?
|
|
8
8
|
private var completion: ((Result<Void, Error>) -> Void)?
|
|
9
9
|
private var finished = false
|
|
10
|
+
private let facts: MacHotspotAuthorizationFacts
|
|
11
|
+
|
|
12
|
+
init(facts: MacHotspotAuthorizationFacts = MacHotspotAuthorizationFacts()) {
|
|
13
|
+
self.facts = facts
|
|
14
|
+
super.init()
|
|
15
|
+
}
|
|
10
16
|
|
|
11
17
|
func start(completion: @escaping (Result<Void, Error>) -> Void) {
|
|
12
18
|
DispatchQueue.main.async {
|
|
@@ -15,7 +21,7 @@ final class MacHotspotAuthorization: NSObject, CLLocationManagerDelegate {
|
|
|
15
21
|
let manager = CLLocationManager()
|
|
16
22
|
self.manager = manager
|
|
17
23
|
manager.delegate = self
|
|
18
|
-
self.handle(manager.authorizationStatus)
|
|
24
|
+
self.handle(manager.authorizationStatus, getter: .instanceInitial)
|
|
19
25
|
if manager.authorizationStatus == .notDetermined { manager.requestWhenInUseAuthorization() }
|
|
20
26
|
}
|
|
21
27
|
}
|
|
@@ -25,7 +31,7 @@ final class MacHotspotAuthorization: NSObject, CLLocationManagerDelegate {
|
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
|
|
28
|
-
handle(manager.authorizationStatus)
|
|
34
|
+
handle(manager.authorizationStatus, getter: .instanceCallback)
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
static func isAuthorized(_ status: CLAuthorizationStatus) -> Bool {
|
|
@@ -36,14 +42,16 @@ final class MacHotspotAuthorization: NSObject, CLLocationManagerDelegate {
|
|
|
36
42
|
return false
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
private func handle(_ status: CLAuthorizationStatus) {
|
|
45
|
+
private func handle(_ status: CLAuthorizationStatus, getter: MacHotspotAuthorizationFacts.Getter) {
|
|
46
|
+
let foreground = MacHotspotAuthorizationFacts.foreground()
|
|
47
|
+
if !finished { facts.observeInstance(raw: status.rawValue, getter: getter, foreground: foreground) }
|
|
40
48
|
if Self.isAuthorized(status) { finish(.success(())); return }
|
|
41
49
|
switch status {
|
|
42
50
|
case .denied, .restricted:
|
|
43
|
-
finish(.failure(
|
|
51
|
+
finish(.failure(facts.failure("Location access is required to identify the glasses hotspot on Mac", raw: status.rawValue, getter: getter, foreground: foreground)))
|
|
44
52
|
case .notDetermined: break
|
|
45
53
|
default:
|
|
46
|
-
finish(.failure(
|
|
54
|
+
finish(.failure(facts.failure("Mac hotspot Location authorization is unavailable", raw: status.rawValue, getter: getter, foreground: foreground)))
|
|
47
55
|
}
|
|
48
56
|
}
|
|
49
57
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
#if canImport(UIKit)
|
|
3
|
+
import UIKit
|
|
4
|
+
#elseif canImport(AppKit)
|
|
5
|
+
import AppKit
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
/// Diagnostic observations only. These facts never authorize a network read or a join.
|
|
9
|
+
final class MacHotspotAuthorizationFacts {
|
|
10
|
+
enum Getter: String { case instanceInitial = "instance-initial", instanceCallback = "instance-callback", staticSSID = "static-ssid" }
|
|
11
|
+
enum Foreground: String { case active, inactive, background, unknown }
|
|
12
|
+
private let lock = NSLock()
|
|
13
|
+
private var instance: (raw: Int32, getter: Getter, foreground: Foreground)?
|
|
14
|
+
private var initialCallbackObserved = false
|
|
15
|
+
private let pid = ProcessInfo.processInfo.processIdentifier
|
|
16
|
+
private let bundleID = Bundle.main.bundleIdentifier.flatMap { value in
|
|
17
|
+
value.range(of: "^[A-Za-z0-9_.-]{1,128}$", options: .regularExpression) == nil ? nil : value
|
|
18
|
+
} ?? "unknown"
|
|
19
|
+
|
|
20
|
+
/// UIKit/AppKit state is sampled only on its owning thread. A worker read stays unknown.
|
|
21
|
+
static func foreground() -> Foreground {
|
|
22
|
+
guard Thread.isMainThread else { return .unknown }
|
|
23
|
+
#if canImport(UIKit)
|
|
24
|
+
switch UIApplication.shared.applicationState {
|
|
25
|
+
case .active: return .active
|
|
26
|
+
case .inactive: return .inactive
|
|
27
|
+
case .background: return .background
|
|
28
|
+
@unknown default: return .unknown
|
|
29
|
+
}
|
|
30
|
+
#elseif canImport(AppKit)
|
|
31
|
+
return NSApplication.shared.isActive ? .active : .inactive
|
|
32
|
+
#else
|
|
33
|
+
return .unknown
|
|
34
|
+
#endif
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func observeInstance(raw: Int32, getter: Getter, foreground: Foreground) {
|
|
38
|
+
lock.lock(); defer { lock.unlock() }
|
|
39
|
+
instance = (raw, getter, foreground)
|
|
40
|
+
if getter == .instanceCallback { initialCallbackObserved = true }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Only enums and this process's identity cross the existing bounded error bridge.
|
|
44
|
+
func failure(_ message: String, raw: Int32, getter: Getter, foreground: Foreground) -> LocalMediaError {
|
|
45
|
+
lock.lock(); defer { lock.unlock() }
|
|
46
|
+
let instanceRaw = instance.map { String($0.raw) } ?? "unknown"
|
|
47
|
+
let instanceGetter = instance?.getter.rawValue ?? "unknown"
|
|
48
|
+
let instanceForeground = instance?.foreground.rawValue ?? "unknown"
|
|
49
|
+
return LocalMediaError("\(message) [location raw=\(raw) getter=\(getter.rawValue) foreground=\(foreground.rawValue) instanceRaw=\(instanceRaw) instanceGetter=\(instanceGetter) instanceForeground=\(instanceForeground) initialCallbackObserved=\(initialCallbackObserved) pid=\(pid) bundle=\(bundleID)]")
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -239,14 +239,15 @@ public final class GlassesHotspotNetwork {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
private func authorizeMacAssociation(ssid: String, passphrase: String, generation gen: Int, deadline: TimeInterval) {
|
|
242
|
-
let
|
|
242
|
+
let facts = MacHotspotAuthorizationFacts()
|
|
243
|
+
let authorization = MacHotspotAuthorization(facts: facts)
|
|
243
244
|
macAuthorization = authorization
|
|
244
245
|
authorization.start { result in
|
|
245
246
|
self.queue.async {
|
|
246
247
|
guard gen == self.generation, !self.cancelled else { return }
|
|
247
248
|
self.macAuthorization = nil
|
|
248
249
|
switch result {
|
|
249
|
-
case .success: self.applyMacAssociation(ssid: ssid, passphrase: passphrase, generation: gen, deadline: deadline)
|
|
250
|
+
case .success: self.applyMacAssociation(ssid: ssid, passphrase: passphrase, generation: gen, deadline: deadline, authorizationFacts: facts)
|
|
250
251
|
case let .failure(error):
|
|
251
252
|
self.finishJoin(.failure(error)); self.finishLeave()
|
|
252
253
|
}
|
|
@@ -254,8 +255,8 @@ public final class GlassesHotspotNetwork {
|
|
|
254
255
|
}
|
|
255
256
|
}
|
|
256
257
|
|
|
257
|
-
private func applyMacAssociation(ssid: String, passphrase: String, generation gen: Int, deadline: TimeInterval) {
|
|
258
|
-
let association = MacHotspotAssociation(deadline: deadline)
|
|
258
|
+
private func applyMacAssociation(ssid: String, passphrase: String, generation gen: Int, deadline: TimeInterval, authorizationFacts: MacHotspotAuthorizationFacts) {
|
|
259
|
+
let association = MacHotspotAssociation(deadline: deadline, authorizationFacts: authorizationFacts)
|
|
259
260
|
macAssociation = association
|
|
260
261
|
applying = true
|
|
261
262
|
macWorker.async {
|