Improve error messaging when installing the Privileged Helper Tool (#103)

* Improve error messaging when installing the Privileged Helper Tool

* Squash those linter warnings

* Fix typo
This commit is contained in:
Nindi Gill 2023-10-29 20:42:12 +11:00 committed by GitHub
parent 29238d1959
commit c5aea7eddc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 35 deletions

View file

@ -10,7 +10,7 @@ import Foundation
/// Helper struct to update a Property List key-pair value. /// Helper struct to update a Property List key-pair value.
struct PropertyListUpdater { struct PropertyListUpdater {
/// Edit a key-pair value in a Property List. /// Update a key-pair value in a Property List.
/// ///
/// - Parameters: /// - Parameters:
/// - url: The URL of the property list to be updated. /// - url: The URL of the property list to be updated.

View file

@ -10,4 +10,5 @@ import SwiftUI
enum FirmwareAlertType: String { enum FirmwareAlertType: String {
case compatibility = "Compatiblity" case compatibility = "Compatiblity"
case helperTool = "Helper Tool" case helperTool = "Helper Tool"
case error = "Error"
} }

View file

@ -10,4 +10,5 @@ enum InstallerAlertType: String {
case helperTool = "Helper Tool" case helperTool = "Helper Tool"
case fullDiskAccess = "Full Disk Access" case fullDiskAccess = "Full Disk Access"
case cacheDirectory = "Cache Directory" case cacheDirectory = "Cache Directory"
case error = "Error"
} }

View file

@ -23,6 +23,7 @@ struct ListRowFirmware: View {
@State private var showAlert: Bool = false @State private var showAlert: Bool = false
@State private var showSavePanel: Bool = false @State private var showSavePanel: Bool = false
@State private var downloading: Bool = false @State private var downloading: Bool = false
@State private var error: Error?
private let length: CGFloat = 48 private let length: CGFloat = 48
private let spacing: CGFloat = 5 private let spacing: CGFloat = 5
private let padding: CGFloat = 3 private let padding: CGFloat = 3
@ -34,6 +35,14 @@ struct ListRowFirmware: View {
return "This macOS Firmware download cannot be used to restore macOS on this \(architecture.description) Mac.\n\nAre you sure you want to continue?" return "This macOS Firmware download cannot be used to restore macOS on this \(architecture.description) Mac.\n\nAre you sure you want to continue?"
} }
private var errorMessage: String {
if let error: BlessError = error as? BlessError {
return error.description
}
return error?.localizedDescription ?? ""
}
var body: some View { var body: some View {
HStack { HStack {
@ -68,10 +77,16 @@ struct ListRowFirmware: View {
case .helperTool: case .helperTool:
return Alert( return Alert(
title: Text("Privileged Helper Tool not installed!"), title: Text("Privileged Helper Tool not installed!"),
message: Text("The Mist Privileged Helper Tool is required to perform Administrator tasks when downloading macOS Firmwares"), message: Text("The Mist Privileged Helper Tool is required to perform Administrator tasks when downloading macOS Firmwares."),
primaryButton: .default(Text("Install...")) { installPrivilegedHelperTool() }, primaryButton: .default(Text("Install...")) { Task { installPrivilegedHelperTool() } },
secondaryButton: .default(Text("Cancel")) secondaryButton: .default(Text("Cancel"))
) )
case .error:
return Alert(
title: Text("An error has occured!"),
message: Text(errorMessage),
dismissButton: .default(Text("OK"))
)
} }
} }
.onChange(of: showSavePanel) { boolean in .onChange(of: showSavePanel) { boolean in
@ -132,7 +147,13 @@ struct ListRowFirmware: View {
} }
private func installPrivilegedHelperTool() { private func installPrivilegedHelperTool() {
try? PrivilegedHelperManager.shared.authorizeAndBless() do {
try PrivilegedHelperManager.shared.authorizeAndBless()
} catch {
self.error = error
alertType = .error
showAlert = true
}
} }
} }

View file

@ -48,6 +48,7 @@ struct ListRowInstaller: View {
@State private var showOpenPanel: Bool = false @State private var showOpenPanel: Bool = false
@State private var exports: [InstallerExportType] = [] @State private var exports: [InstallerExportType] = []
@State private var volume: InstallerVolume? @State private var volume: InstallerVolume?
@State private var error: Error?
private let length: CGFloat = 48 private let length: CGFloat = 48
private let spacing: CGFloat = 5 private let spacing: CGFloat = 5
private let padding: CGFloat = 3 private let padding: CGFloat = 3
@ -62,6 +63,14 @@ struct ListRowInstaller: View {
private var cacheDirectoryMessage: String { private var cacheDirectoryMessage: String {
"The cache directory has incorrect ownership and/or permissions, which will cause issues caching macOS Installers.\n\nRepair the cache directory ownership and/or permissions and try again." "The cache directory has incorrect ownership and/or permissions, which will cause issues caching macOS Installers.\n\nRepair the cache directory ownership and/or permissions and try again."
} }
private var errorMessage: String {
if let error: BlessError = error as? BlessError {
return error.description
}
return error?.localizedDescription ?? ""
}
var body: some View { var body: some View {
HStack { HStack {
@ -97,36 +106,7 @@ struct ListRowInstaller: View {
.clipShape(Capsule()) .clipShape(Capsule())
} }
.alert(isPresented: $showAlert) { .alert(isPresented: $showAlert) {
switch alertType { alert(for: alertType)
case .compatibility:
return Alert(
title: Text("macOS Installer not compatible!"),
message: Text(compatibilityMessage),
primaryButton: .default(Text("Cancel")),
secondaryButton: .default(Text("Continue")) { Task { validate() } }
)
case .helperTool:
return Alert(
title: Text("Privileged Helper Tool not installed!"),
message: Text("The Mist Privileged Helper Tool is required to perform Administrator tasks when creating macOS Installers."),
primaryButton: .default(Text("Install...")) { installPrivilegedHelperTool() },
secondaryButton: .default(Text("Cancel"))
)
case .fullDiskAccess:
return Alert(
title: Text("Full Disk Access required!"),
message: Text("Mist requires Full Disk Access to perform Administrator tasks when creating macOS Installers."),
primaryButton: .default(Text("Allow...")) { openFullDiskAccessPreferences() },
secondaryButton: .default(Text("Cancel"))
)
case .cacheDirectory:
return Alert(
title: Text("Cache directory settings incorrect!"),
message: Text(cacheDirectoryMessage),
primaryButton: .default(Text("Repair...")) { Task { try await repairCacheDirectoryOwnershipAndPermissions() } },
secondaryButton: .default(Text("Cancel"))
)
}
} }
.onChange(of: showOpenPanel) { boolean in .onChange(of: showOpenPanel) { boolean in
@ -309,7 +289,13 @@ struct ListRowInstaller: View {
} }
private func installPrivilegedHelperTool() { private func installPrivilegedHelperTool() {
try? PrivilegedHelperManager.shared.authorizeAndBless() do {
try PrivilegedHelperManager.shared.authorizeAndBless()
} catch {
self.error = error
alertType = .error
showAlert = true
}
} }
private func openFullDiskAccessPreferences() { private func openFullDiskAccessPreferences() {
@ -326,6 +312,45 @@ struct ListRowInstaller: View {
let ownerAccountName: String = NSUserName() let ownerAccountName: String = NSUserName()
try await FileAttributesUpdater.update(url: url, ownerAccountName: ownerAccountName) try await FileAttributesUpdater.update(url: url, ownerAccountName: ownerAccountName)
} }
private func alert(for alertType: InstallerAlertType) -> Alert {
switch alertType {
case .compatibility:
return Alert(
title: Text("macOS Installer not compatible!"),
message: Text(compatibilityMessage),
primaryButton: .default(Text("Cancel")),
secondaryButton: .default(Text("Continue")) { Task { validate() } }
)
case .helperTool:
return Alert(
title: Text("Privileged Helper Tool not installed!"),
message: Text("The Mist Privileged Helper Tool is required to perform Administrator tasks when creating macOS Installers."),
primaryButton: .default(Text("Install...")) { Task { installPrivilegedHelperTool() } },
secondaryButton: .default(Text("Cancel"))
)
case .fullDiskAccess:
return Alert(
title: Text("Full Disk Access required!"),
message: Text("Mist requires Full Disk Access to perform Administrator tasks when creating macOS Installers."),
primaryButton: .default(Text("Allow...")) { openFullDiskAccessPreferences() },
secondaryButton: .default(Text("Cancel"))
)
case .cacheDirectory:
return Alert(
title: Text("Cache directory settings incorrect!"),
message: Text(cacheDirectoryMessage),
primaryButton: .default(Text("Repair...")) { Task { try await repairCacheDirectoryOwnershipAndPermissions() } },
secondaryButton: .default(Text("Cancel"))
)
case .error:
return Alert(
title: Text("An error has occured!"),
message: Text(errorMessage),
dismissButton: .default(Text("OK"))
)
}
}
} }
struct ListRowInstaller_Previews: PreviewProvider { struct ListRowInstaller_Previews: PreviewProvider {