Add Full Disk Access verification

This commit is contained in:
Nindi Gill 2023-06-01 15:59:38 +10:00
parent 104f4c6da4
commit 49eae0e017
No known key found for this signature in database
GPG key ID: FF9A7FD590D4F4B1
4 changed files with 97 additions and 0 deletions

View file

@ -130,6 +130,8 @@
39FF05F62859850F00A86670 /* SettingsFirmwaresView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39FF05F52859850F00A86670 /* SettingsFirmwaresView.swift */; }; 39FF05F62859850F00A86670 /* SettingsFirmwaresView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39FF05F52859850F00A86670 /* SettingsFirmwaresView.swift */; };
39FF05F82859851800A86670 /* SettingsApplicationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39FF05F72859851800A86670 /* SettingsApplicationsView.swift */; }; 39FF05F82859851800A86670 /* SettingsApplicationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39FF05F72859851800A86670 /* SettingsApplicationsView.swift */; };
39FF05FA285985DD00A86670 /* SettingsAboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39FF05F9285985DD00A86670 /* SettingsAboutView.swift */; }; 39FF05FA285985DD00A86670 /* SettingsAboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39FF05F9285985DD00A86670 /* SettingsAboutView.swift */; };
573A235E2A285E8900EC9470 /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 573A235D2A285E8900EC9470 /* SQLite */; };
573A23602A285EAE00EC9470 /* FullDiskAccessVerifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 573A235F2A285EAE00EC9470 /* FullDiskAccessVerifier.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@ -270,6 +272,7 @@
39FF05F52859850F00A86670 /* SettingsFirmwaresView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFirmwaresView.swift; sourceTree = "<group>"; }; 39FF05F52859850F00A86670 /* SettingsFirmwaresView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFirmwaresView.swift; sourceTree = "<group>"; };
39FF05F72859851800A86670 /* SettingsApplicationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsApplicationsView.swift; sourceTree = "<group>"; }; 39FF05F72859851800A86670 /* SettingsApplicationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsApplicationsView.swift; sourceTree = "<group>"; };
39FF05F9285985DD00A86670 /* SettingsAboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAboutView.swift; sourceTree = "<group>"; }; 39FF05F9285985DD00A86670 /* SettingsAboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAboutView.swift; sourceTree = "<group>"; };
573A235F2A285EAE00EC9470 /* FullDiskAccessVerifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullDiskAccessVerifier.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -277,6 +280,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
573A235E2A285E8900EC9470 /* SQLite in Frameworks */,
3935F4C5286B546A00760AB0 /* Sparkle in Frameworks */, 3935F4C5286B546A00760AB0 /* Sparkle in Frameworks */,
390451DF28573FAA00E0B563 /* Yams in Frameworks */, 390451DF28573FAA00E0B563 /* Yams in Frameworks */,
39CF55AA286154A5006FB5D2 /* Blessed in Frameworks */, 39CF55AA286154A5006FB5D2 /* Blessed in Frameworks */,
@ -374,6 +378,7 @@
39CA25E22941D8BB0030711E /* FileAttributesUpdater.swift */, 39CA25E22941D8BB0030711E /* FileAttributesUpdater.swift */,
39CF56162861BE66006FB5D2 /* FileCopier.swift */, 39CF56162861BE66006FB5D2 /* FileCopier.swift */,
398734C728601FFC00B4C357 /* FileMover.swift */, 398734C728601FFC00B4C357 /* FileMover.swift */,
573A235F2A285EAE00EC9470 /* FullDiskAccessVerifier.swift */,
39D68B882861369B00A7848C /* InstallerCreator.swift */, 39D68B882861369B00A7848C /* InstallerCreator.swift */,
39CF56302862A8C5006FB5D2 /* InstallMediaCreator.swift */, 39CF56302862A8C5006FB5D2 /* InstallMediaCreator.swift */,
39CF562E2862A797006FB5D2 /* ISOConverter.swift */, 39CF562E2862A797006FB5D2 /* ISOConverter.swift */,
@ -560,6 +565,7 @@
39CF55A9286154A5006FB5D2 /* Blessed */, 39CF55A9286154A5006FB5D2 /* Blessed */,
39CF55B128615D30006FB5D2 /* SecureXPC */, 39CF55B128615D30006FB5D2 /* SecureXPC */,
3935F4C4286B546A00760AB0 /* Sparkle */, 3935F4C4286B546A00760AB0 /* Sparkle */,
573A235D2A285E8900EC9470 /* SQLite */,
); );
productName = Mist; productName = Mist;
productReference = 390451A62856E1D900E0B563 /* Mist.app */; productReference = 390451A62856E1D900E0B563 /* Mist.app */;
@ -639,6 +645,7 @@
39CF55A8286154A5006FB5D2 /* XCRemoteSwiftPackageReference "Blessed" */, 39CF55A8286154A5006FB5D2 /* XCRemoteSwiftPackageReference "Blessed" */,
39CF55B028615D30006FB5D2 /* XCRemoteSwiftPackageReference "SecureXPC" */, 39CF55B028615D30006FB5D2 /* XCRemoteSwiftPackageReference "SecureXPC" */,
3935F4C3286B546A00760AB0 /* XCRemoteSwiftPackageReference "Sparkle" */, 3935F4C3286B546A00760AB0 /* XCRemoteSwiftPackageReference "Sparkle" */,
573A235C2A285E8900EC9470 /* XCRemoteSwiftPackageReference "SQLite" */,
); );
productRefGroup = 390451A72856E1D900E0B563 /* Products */; productRefGroup = 390451A72856E1D900E0B563 /* Products */;
projectDirPath = ""; projectDirPath = "";
@ -803,6 +810,7 @@
39CA25E32941D8BB0030711E /* FileAttributesUpdater.swift in Sources */, 39CA25E32941D8BB0030711E /* FileAttributesUpdater.swift in Sources */,
3935F4AB286B04BC00760AB0 /* HelperToolInfoPropertyList.swift in Sources */, 3935F4AB286B04BC00760AB0 /* HelperToolInfoPropertyList.swift in Sources */,
393F35BC28641181005B7165 /* RefreshState.swift in Sources */, 393F35BC28641181005B7165 /* RefreshState.swift in Sources */,
573A23602A285EAE00EC9470 /* FullDiskAccessVerifier.swift in Sources */,
390451CA2856F1D300E0B563 /* ScaledImage.swift in Sources */, 390451CA2856F1D300E0B563 /* ScaledImage.swift in Sources */,
39252A95285BF83D00956C74 /* MistTask.swift in Sources */, 39252A95285BF83D00956C74 /* MistTask.swift in Sources */,
39CF56272861E10F006FB5D2 /* Codesigner.swift in Sources */, 39CF56272861E10F006FB5D2 /* Codesigner.swift in Sources */,
@ -1238,6 +1246,14 @@
minimumVersion = 0.8.0; minimumVersion = 0.8.0;
}; };
}; };
573A235C2A285E8900EC9470 /* XCRemoteSwiftPackageReference "SQLite" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/stephencelis/SQLite.swift";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.14.1;
};
};
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
@ -1271,6 +1287,11 @@
package = 39CF55B028615D30006FB5D2 /* XCRemoteSwiftPackageReference "SecureXPC" */; package = 39CF55B028615D30006FB5D2 /* XCRemoteSwiftPackageReference "SecureXPC" */;
productName = SecureXPC; productName = SecureXPC;
}; };
573A235D2A285E8900EC9470 /* SQLite */ = {
isa = XCSwiftPackageProductDependency;
package = 573A235C2A285E8900EC9470 /* XCRemoteSwiftPackageReference "SQLite" */;
productName = SQLite;
};
/* End XCSwiftPackageProductDependency section */ /* End XCSwiftPackageProductDependency section */
}; };
rootObject = 3904519E2856E1D800E0B563 /* Project object */; rootObject = 3904519E2856E1D800E0B563 /* Project object */;

View file

@ -0,0 +1,46 @@
//
// FullDiskAccessVerifier.swift
// Mist
//
// Created by Nindi Gill on 1/6/2023.
//
import SQLite
/// Helper struct to verify Full Disk Access.
struct FullDiskAccessVerifier {
private enum AuthValue: Int {
case denied = 0
case unknown = 1
case allowed = 2
case limited = 3
}
/// TCC Service identifier for Full Disk Access
private static let kTCCServiceSystemPolicyAllFiles: String = "kTCCServiceSystemPolicyAllFiles"
/// Verifies if the app has Full Disk Access.
///
/// - Returns: `true` if the app has Full Disk Access, otherwise `false`.
static func isAllowed() -> Bool {
do {
let database: Connection = try Connection("/Library/Application Support/com.apple.TCC/TCC.db")
let service: Expression = Expression<String>("service")
let client: Expression = Expression<String>("client")
let authValue: Expression = Expression<Int>("auth_value")
let access: Table = Table("access").filter(service == kTCCServiceSystemPolicyAllFiles && client == String.appIdentifier)
var allowed: Bool = false
for row in try database.prepare(access) where row[authValue] == AuthValue.allowed.rawValue {
allowed = true
break
}
return allowed
} catch {
// print(error.localizedDescription)
return false
}
}
}

View file

@ -8,5 +8,6 @@
enum DownloadAlertType: String { enum DownloadAlertType: String {
case compatibility = "Compatiblity" case compatibility = "Compatiblity"
case helperTool = "Helper Tool" case helperTool = "Helper Tool"
case fullDiskAccess = "Full Disk Access"
case cacheDirectory = "Cache Directory" case cacheDirectory = "Cache Directory"
} }

View file

@ -49,6 +49,12 @@ struct ListRow: View {
private var privilegedHelperToolMessage: String { private var privilegedHelperToolMessage: String {
"The Mist Privileged Helper Tool is required to perform Administrator tasks when \(type == .firmware ? "downloading macOS Firmwares" : "creating macOS Installers")." "The Mist Privileged Helper Tool is required to perform Administrator tasks when \(type == .firmware ? "downloading macOS Firmwares" : "creating macOS Installers")."
} }
private var fullDiskAccessTitle: String {
"Full Disk Access required!"
}
private var fullDiskAccessMessage: String {
"Mist requires Full Disk Access to perform Administrator tasks when creating macOS Installers."
}
private var cacheDirectoryTitle: String { private var cacheDirectoryTitle: String {
"Cache directory settings incorrect!" "Cache directory settings incorrect!"
} }
@ -99,6 +105,13 @@ struct ListRow: View {
primaryButton: .default(Text("Install...")) { installPrivilegedHelperTool() }, primaryButton: .default(Text("Install...")) { installPrivilegedHelperTool() },
secondaryButton: .default(Text("Cancel")) secondaryButton: .default(Text("Cancel"))
) )
case .fullDiskAccess:
return Alert(
title: Text(fullDiskAccessTitle),
message: Text(fullDiskAccessMessage),
primaryButton: .default(Text("Allow...")) { openFullDiskAccessPreferences() },
secondaryButton: .default(Text("Cancel"))
)
case .cacheDirectory: case .cacheDirectory:
return Alert( return Alert(
title: Text(cacheDirectoryTitle), title: Text(cacheDirectoryTitle),
@ -123,6 +136,13 @@ struct ListRow: View {
return return
} }
guard type == .installer,
FullDiskAccessVerifier.isAllowed() else {
alertType = .fullDiskAccess
showAlert = true
return
}
if cacheDownloads { if cacheDownloads {
do { do {
@ -165,6 +185,15 @@ struct ListRow: View {
try? PrivilegedHelperManager.shared.authorizeAndBless() try? PrivilegedHelperManager.shared.authorizeAndBless()
} }
private func openFullDiskAccessPreferences() {
guard let url: URL = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") else {
return
}
NSWorkspace.shared.open(url)
}
private func repairCacheDirectoryOwnershipAndPermissions() async throws { private func repairCacheDirectoryOwnershipAndPermissions() async throws {
let url: URL = URL(fileURLWithPath: cacheDirectory) let url: URL = URL(fileURLWithPath: cacheDirectory)
let ownerAccountName: String = NSUserName() let ownerAccountName: String = NSUserName()