fix: remove nonessential boss agent permission requests
This commit is contained in:
@@ -1,22 +1,10 @@
|
||||
import Cocoa
|
||||
import WebKit
|
||||
import ApplicationServices
|
||||
import AVFoundation
|
||||
import IOKit.hid
|
||||
import Network
|
||||
import UserNotifications
|
||||
|
||||
private let bossInputMonitoringTapCallback: CGEventTapCallBack = { _, _, event, _ in
|
||||
Unmanaged.passUnretained(event)
|
||||
}
|
||||
|
||||
final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
|
||||
private var window: NSWindow?
|
||||
private var webView: WKWebView?
|
||||
private var inputMonitoringTap: CFMachPort?
|
||||
private var globalKeyMonitor: Any?
|
||||
private var inputMonitoringManager: IOHIDManager?
|
||||
private var localNetworkBrowser: NWBrowser?
|
||||
private var activeTab = "overview"
|
||||
|
||||
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||
@@ -166,7 +154,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
|
||||
private func handleBossAgentDeepLink(_ url: URL) {
|
||||
if url.host == "permissions" && url.path == "/open" {
|
||||
handlePermissionTarget(
|
||||
queryValue("target", in: url) ?? "all",
|
||||
queryValue("target", in: url) ?? "core",
|
||||
returnTab: queryValue("returnTab", in: url) ?? "permissions"
|
||||
)
|
||||
return
|
||||
@@ -206,22 +194,23 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
|
||||
|
||||
private func handlePermissionSetupNavigation(_ url: URL) {
|
||||
handlePermissionTarget(
|
||||
queryValue("target", in: url) ?? "all",
|
||||
queryValue("target", in: url) ?? "core",
|
||||
returnTab: queryValue("returnTab", in: url) ?? activeTab
|
||||
)
|
||||
}
|
||||
|
||||
private func handlePermissionTarget(_ target: String, returnTab rawReturnTab: String) {
|
||||
let permissionTarget = normalizedPermissionTarget(target)
|
||||
let returnTab = normalizedTab(rawReturnTab)
|
||||
activeTab = returnTab
|
||||
|
||||
UserDefaults.standard.set(target, forKey: "lastPermissionRequestTarget")
|
||||
UserDefaults.standard.set(permissionTarget, forKey: "lastPermissionRequestTarget")
|
||||
UserDefaults.standard.set(Date().timeIntervalSince1970, forKey: "lastPermissionRequestAt")
|
||||
NSLog("boss-agent permission request target=%@ returnTab=%@", target, returnTab)
|
||||
NSLog("boss-agent permission request target=%@ returnTab=%@", permissionTarget, returnTab)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
requestNativePermission(for: target)
|
||||
requestNativePermission(for: permissionTarget)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.45) { [weak self] in
|
||||
if let settingsUrl = self?.systemSettingsUrl(for: target) {
|
||||
if let settingsUrl = self?.systemSettingsUrl(for: permissionTarget) {
|
||||
NSWorkspace.shared.open(settingsUrl)
|
||||
}
|
||||
}
|
||||
@@ -235,9 +224,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
|
||||
[
|
||||
URLQueryItem(name: "nativeAccessibility", value: AXIsProcessTrusted() ? "granted" : "missing"),
|
||||
URLQueryItem(name: "nativeScreenRecording", value: screenRecordingStatus()),
|
||||
URLQueryItem(name: "nativeInputMonitoring", value: inputMonitoringStatus()),
|
||||
URLQueryItem(name: "nativeMicrophone", value: microphonePermissionStatus()),
|
||||
URLQueryItem(name: "nativeCamera", value: cameraPermissionStatus()),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -248,63 +234,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
private func microphonePermissionStatus() -> String {
|
||||
switch AVCaptureDevice.authorizationStatus(for: .audio) {
|
||||
case .authorized:
|
||||
return "granted"
|
||||
case .denied, .restricted:
|
||||
return "missing"
|
||||
case .notDetermined:
|
||||
return "unknown"
|
||||
@unknown default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
private func cameraPermissionStatus() -> String {
|
||||
switch AVCaptureDevice.authorizationStatus(for: .video) {
|
||||
case .authorized:
|
||||
return "granted"
|
||||
case .denied, .restricted:
|
||||
return "missing"
|
||||
case .notDetermined:
|
||||
return "unknown"
|
||||
@unknown default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
private func inputMonitoringStatus() -> String {
|
||||
if #available(macOS 10.15, *) {
|
||||
return CGPreflightListenEventAccess() ? "granted" : "missing"
|
||||
}
|
||||
|
||||
switch IOHIDCheckAccess(kIOHIDRequestTypeListenEvent) {
|
||||
case kIOHIDAccessTypeGranted:
|
||||
return "granted"
|
||||
case kIOHIDAccessTypeDenied:
|
||||
return "missing"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
private func requestNativePermission(for target: String) {
|
||||
let targets: [String]
|
||||
if target == "core" {
|
||||
targets = ["accessibility", "screenRecording"]
|
||||
} else if target == "all" {
|
||||
targets = [
|
||||
"accessibility",
|
||||
"screenRecording",
|
||||
"automation",
|
||||
"fullDiskAccess",
|
||||
"inputMonitoring",
|
||||
"notifications",
|
||||
"microphone",
|
||||
"camera",
|
||||
"localNetwork",
|
||||
]
|
||||
} else {
|
||||
targets = [target]
|
||||
}
|
||||
@@ -320,20 +253,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
|
||||
requestAccessibilityPermission()
|
||||
case "screenRecording":
|
||||
requestScreenRecordingPermission()
|
||||
case "automation":
|
||||
requestAutomationPermission()
|
||||
case "fullDiskAccess":
|
||||
preflightFullDiskAccess()
|
||||
case "inputMonitoring":
|
||||
requestInputMonitoringPermission()
|
||||
case "notifications":
|
||||
requestNotificationPermission()
|
||||
case "microphone":
|
||||
requestMicrophonePermission()
|
||||
case "camera":
|
||||
requestCameraPermission()
|
||||
case "localNetwork":
|
||||
requestLocalNetworkPermission()
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -345,18 +264,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
|
||||
_ = AXIsProcessTrustedWithOptions(options)
|
||||
}
|
||||
|
||||
private func requestMicrophonePermission() {
|
||||
if AVCaptureDevice.authorizationStatus(for: .audio) == .notDetermined {
|
||||
AVCaptureDevice.requestAccess(for: .audio) { _ in }
|
||||
}
|
||||
}
|
||||
|
||||
private func requestCameraPermission() {
|
||||
if AVCaptureDevice.authorizationStatus(for: .video) == .notDetermined {
|
||||
AVCaptureDevice.requestAccess(for: .video) { _ in }
|
||||
}
|
||||
}
|
||||
|
||||
private func requestScreenRecordingPermission() {
|
||||
if #available(macOS 10.15, *) {
|
||||
_ = CGRequestScreenCaptureAccess()
|
||||
@@ -365,105 +272,22 @@ final class AppDelegate: NSObject, NSApplicationDelegate, WKNavigationDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private func requestAutomationPermission() {
|
||||
let script = NSAppleScript(source: "tell application \"Finder\" to get name")
|
||||
var error: NSDictionary?
|
||||
_ = script?.executeAndReturnError(&error)
|
||||
}
|
||||
|
||||
private func preflightFullDiskAccess() {
|
||||
let candidatePaths = [
|
||||
"\(NSHomeDirectory())/Library/Safari/Bookmarks.plist",
|
||||
"\(NSHomeDirectory())/Library/Mail",
|
||||
"/Library/Application Support/com.apple.TCC/TCC.db",
|
||||
]
|
||||
for path in candidatePaths {
|
||||
if FileManager.default.fileExists(atPath: path) {
|
||||
_ = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func requestInputMonitoringPermission() {
|
||||
var listenRequestResult = false
|
||||
if #available(macOS 10.15, *) {
|
||||
listenRequestResult = CGRequestListenEventAccess()
|
||||
} else {
|
||||
listenRequestResult = IOHIDRequestAccess(kIOHIDRequestTypeListenEvent)
|
||||
}
|
||||
NSLog("boss-agent input monitoring listen request result=%@", listenRequestResult ? "true" : "false")
|
||||
|
||||
if globalKeyMonitor == nil {
|
||||
globalKeyMonitor = NSEvent.addGlobalMonitorForEvents(matching: [.keyDown]) { _ in }
|
||||
}
|
||||
preflightKeyboardStateRead()
|
||||
primeInputMonitoringHidPath()
|
||||
|
||||
let eventMask = CGEventMask(1 << CGEventType.keyDown.rawValue)
|
||||
inputMonitoringTap = CGEvent.tapCreate(
|
||||
tap: .cgSessionEventTap,
|
||||
place: .headInsertEventTap,
|
||||
options: .listenOnly,
|
||||
eventsOfInterest: eventMask,
|
||||
callback: bossInputMonitoringTapCallback,
|
||||
userInfo: nil
|
||||
)
|
||||
if let tap = inputMonitoringTap {
|
||||
CFMachPortInvalidate(tap)
|
||||
inputMonitoringTap = nil
|
||||
}
|
||||
}
|
||||
|
||||
private func preflightKeyboardStateRead() {
|
||||
for keyCode in [CGKeyCode(0), CGKeyCode(1), CGKeyCode(49), CGKeyCode(53)] {
|
||||
_ = CGEventSource.keyState(.combinedSessionState, key: keyCode)
|
||||
}
|
||||
}
|
||||
|
||||
private func primeInputMonitoringHidPath() {
|
||||
let manager = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone))
|
||||
let keyboardMatching = [
|
||||
kIOHIDDeviceUsagePageKey as String: kHIDPage_GenericDesktop,
|
||||
kIOHIDDeviceUsageKey as String: kHIDUsage_GD_Keyboard,
|
||||
] as CFDictionary
|
||||
IOHIDManagerSetDeviceMatching(manager, keyboardMatching)
|
||||
let openResult = IOHIDManagerOpen(manager, IOOptionBits(kIOHIDOptionsTypeNone))
|
||||
NSLog("boss-agent input monitoring hid open result=%d", openResult)
|
||||
inputMonitoringManager = manager
|
||||
}
|
||||
|
||||
private func requestNotificationPermission() {
|
||||
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { _, _ in }
|
||||
}
|
||||
|
||||
private func requestLocalNetworkPermission() {
|
||||
let parameters = NWParameters.tcp
|
||||
parameters.includePeerToPeer = true
|
||||
let browser = NWBrowser(for: .bonjour(type: "_http._tcp", domain: nil), using: parameters)
|
||||
browser.stateUpdateHandler = { _ in }
|
||||
localNetworkBrowser = browser
|
||||
browser.start(queue: .main)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { [weak self] in
|
||||
self?.localNetworkBrowser?.cancel()
|
||||
self?.localNetworkBrowser = nil
|
||||
}
|
||||
}
|
||||
|
||||
private func systemSettingsUrl(for target: String) -> URL? {
|
||||
let mapping = [
|
||||
"all": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Security",
|
||||
"core": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_Accessibility",
|
||||
"accessibility": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_Accessibility",
|
||||
"screenRecording": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_ScreenCapture",
|
||||
"automation": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_Automation",
|
||||
"fullDiskAccess": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_AllFiles",
|
||||
"inputMonitoring": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_ListenEvent",
|
||||
"notifications": "x-apple.systempreferences:com.apple.Notifications-Settings.extension",
|
||||
"microphone": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_Microphone",
|
||||
"camera": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_Camera",
|
||||
"localNetwork": "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?privacy-localnetwork",
|
||||
]
|
||||
return URL(string: mapping[target] ?? mapping["all"]!)
|
||||
return URL(string: mapping[normalizedPermissionTarget(target)] ?? mapping["core"]!)
|
||||
}
|
||||
|
||||
private func normalizedPermissionTarget(_ target: String) -> String {
|
||||
switch target {
|
||||
case "accessibility", "screenRecording", "core":
|
||||
return target
|
||||
default:
|
||||
return "core"
|
||||
}
|
||||
}
|
||||
|
||||
private func loadFallback() {
|
||||
|
||||
Reference in New Issue
Block a user