#import "Permissions.h" #import #import #import bool Permissions::checkScreenCapture() { // macOS 10.15+ requires screen recording permission if (@available(macOS 10.15, *)) { // CGPreflightScreenCaptureAccess() is unreliable - it can return false // even when permission is granted (especially after code re-signing). // Instead, actually try to capture the screen to verify permission. CGDirectDisplayID displayID = CGMainDisplayID(); CGImageRef image = CGDisplayCreateImage(displayID); if (image != NULL) { // Got an image - permission is granted // Additional check: verify image has actual content (not blank) size_t width = CGImageGetWidth(image); size_t height = CGImageGetHeight(image); CGImageRelease(image); if (width > 0 && height > 0) { return true; } } // Failed to capture - permission not granted or display issue // Fall back to preflight check for triggering dialog return CGPreflightScreenCaptureAccess(); } // Before 10.15, no permission needed return true; } void Permissions::requestScreenCapture() { if (@available(macOS 10.15, *)) { // Trigger system permission dialog CGRequestScreenCaptureAccess(); } } bool Permissions::checkAccessibility() { return AXIsProcessTrusted(); } void Permissions::requestAccessibility() { NSDictionary *options = @{ (__bridge id)kAXTrustedCheckOptionPrompt: @YES }; AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)options); } void Permissions::openScreenCaptureSettings() { if (@available(macOS 10.15, *)) { // Open System Preferences -> Security & Privacy -> Privacy -> Screen Recording NSURL *url = [NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture"]; [[NSWorkspace sharedWorkspace] openURL:url]; } } void Permissions::openAccessibilitySettings() { // Open System Preferences -> Security & Privacy -> Privacy -> Accessibility NSURL *url = [NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"]; [[NSWorkspace sharedWorkspace] openURL:url]; } bool Permissions::checkFullDiskAccess() { // There's no official API to check Full Disk Access. // Try to actually read a protected file that requires FDA. NSString* testPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Safari/Bookmarks.plist"]; NSFileManager* fm = [NSFileManager defaultManager]; if ([fm fileExistsAtPath:testPath]) { // Try to actually read the file (more reliable than isReadableFileAtPath) NSData* data = [NSData dataWithContentsOfFile:testPath]; if (data != nil) { NSLog(@"FDA check: OK (can read Safari bookmarks)"); return true; } else { NSLog(@"FDA check: FAILED (Safari bookmarks exists but unreadable)"); return false; } } // Safari bookmarks doesn't exist, try TCC database testPath = @"/Library/Application Support/com.apple.TCC/TCC.db"; if ([fm fileExistsAtPath:testPath]) { NSData* data = [NSData dataWithContentsOfFile:testPath]; if (data != nil) { NSLog(@"FDA check: OK (can read TCC.db)"); return true; } else { NSLog(@"FDA check: FAILED (TCC.db exists but unreadable)"); return false; } } // No test files exist, assume OK NSLog(@"FDA check: SKIPPED (no test files found)"); return true; } void Permissions::openFullDiskAccessSettings() { // Open System Preferences -> Security & Privacy -> Privacy -> Full Disk Access NSURL *url = [NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"]; [[NSWorkspace sharedWorkspace] openURL:url]; } bool Permissions::checkAllPermissions() { return checkScreenCapture() && checkAccessibility() && checkFullDiskAccess(); } bool Permissions::waitForPermissions(int timeoutSeconds) { int elapsed = 0; while (elapsed < timeoutSeconds) { if (checkAllPermissions()) { return true; } [NSThread sleepForTimeInterval:1.0]; elapsed++; } return false; }