Internal tooling for Mac utility for storage management.

Swift 98.7% JSON 1.1% Markdown 0.2%
FullDiskAccessManager.swift 78 lines (3 KB)
//
//  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()
    }
}

About

Internal tooling for Mac utility for storage management.

0 stars
0 forks