// // FullDiskAccessManager.swift // MUA // // Created by Mitchel Volkering on 21/12/2025. // import Foundation import AppKit import Combine /// Manages Full Disk Access permission checks and user prompts /// Based on Apple's recommended approach: check access, inform user, open System Settings @MainActor final class FullDiskAccessManager: ObservableObject { static let shared = FullDiskAccessManager() @Published var hasFullDiskAccess: Bool = false @Published var hasCheckedAccess: Bool = false private init() { checkAccess() } /// Check if the app has Full Disk Access by attempting to read a protected directory /// Apple recommends checking by trying to access a TCC-protected path func checkAccess() { // These paths are protected by TCC and require Full Disk Access let protectedPaths = [ FileManager.default.homeDirectoryForCurrentUser.appending(path: "Library/Mail"), FileManager.default.homeDirectoryForCurrentUser.appending(path: "Library/Messages"), FileManager.default.homeDirectoryForCurrentUser.appending(path: "Library/Safari"), URL(fileURLWithPath: "/Library/Application Support/com.apple.TCC") ] for path in protectedPaths { if FileManager.default.isReadableFile(atPath: path.path) { hasFullDiskAccess = true hasCheckedAccess = true return } } // Try to actually list contents of a protected directory let testPath = FileManager.default.homeDirectoryForCurrentUser.appending(path: "Library/Mail") do { _ = try FileManager.default.contentsOfDirectory(at: testPath, includingPropertiesForKeys: nil) hasFullDiskAccess = true } catch { // If we get a permission error, we don't have access hasFullDiskAccess = false } hasCheckedAccess = true } /// Opens System Settings to the Full Disk Access pane /// This is the Apple-approved way to guide users to grant permission func openFullDiskAccessSettings() { // macOS 13+ uses the new System Settings URL scheme // x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") { NSWorkspace.shared.open(url) } else { // Fallback: open Security & Privacy preferences if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy") { NSWorkspace.shared.open(url) } } } /// Refresh the access status (call after user returns from System Settings) func refreshAccessStatus() { hasCheckedAccess = false checkAccess() } }