mirror of
https://github.com/ninxsoft/Mist.git
synced 2025-05-14 15:15:05 -04:00
Merge pull request #21 from ninxsoft/feature-better-cache-error-messagign
Feature better cache error messagign
This commit is contained in:
commit
9ef77ff885
12 changed files with 254 additions and 21 deletions
|
@ -94,6 +94,7 @@
|
||||||
398734D028603D9E00B4C357 /* UInt8+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734CF28603D9E00B4C357 /* UInt8+Extension.swift */; };
|
398734D028603D9E00B4C357 /* UInt8+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734CF28603D9E00B4C357 /* UInt8+Extension.swift */; };
|
||||||
398734D228603DE700B4C357 /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D128603DE700B4C357 /* Array+Extension.swift */; };
|
398734D228603DE700B4C357 /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D128603DE700B4C357 /* Array+Extension.swift */; };
|
||||||
398734D4286046B000B4C357 /* UInt32+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D3286046B000B4C357 /* UInt32+Extension.swift */; };
|
398734D4286046B000B4C357 /* UInt32+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D3286046B000B4C357 /* UInt32+Extension.swift */; };
|
||||||
|
39CA25E32941D8BB0030711E /* FileAttributesUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CA25E22941D8BB0030711E /* FileAttributesUpdater.swift */; };
|
||||||
39CB5E3D293F5C2E00CFDBB8 /* Catalog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */; };
|
39CB5E3D293F5C2E00CFDBB8 /* Catalog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */; };
|
||||||
39CB5E3F2941486D00CFDBB8 /* CatalogSeedType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */; };
|
39CB5E3F2941486D00CFDBB8 /* CatalogSeedType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */; };
|
||||||
39CB5E5429418A2900CFDBB8 /* MistTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E5329418A2900CFDBB8 /* MistTests.swift */; };
|
39CB5E5429418A2900CFDBB8 /* MistTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E5329418A2900CFDBB8 /* MistTests.swift */; };
|
||||||
|
@ -239,6 +240,7 @@
|
||||||
398734CF28603D9E00B4C357 /* UInt8+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt8+Extension.swift"; sourceTree = "<group>"; };
|
398734CF28603D9E00B4C357 /* UInt8+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt8+Extension.swift"; sourceTree = "<group>"; };
|
||||||
398734D128603DE700B4C357 /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = "<group>"; };
|
398734D128603DE700B4C357 /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = "<group>"; };
|
||||||
398734D3286046B000B4C357 /* UInt32+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt32+Extension.swift"; sourceTree = "<group>"; };
|
398734D3286046B000B4C357 /* UInt32+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt32+Extension.swift"; sourceTree = "<group>"; };
|
||||||
|
39CA25E22941D8BB0030711E /* FileAttributesUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileAttributesUpdater.swift; sourceTree = "<group>"; };
|
||||||
39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Catalog.swift; sourceTree = "<group>"; };
|
39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Catalog.swift; sourceTree = "<group>"; };
|
||||||
39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogSeedType.swift; sourceTree = "<group>"; };
|
39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogSeedType.swift; sourceTree = "<group>"; };
|
||||||
39CB5E5129418A2900CFDBB8 /* MistTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MistTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
39CB5E5129418A2900CFDBB8 /* MistTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MistTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -373,6 +375,7 @@
|
||||||
39CF56202861C992006FB5D2 /* DiskImageMounter.swift */,
|
39CF56202861C992006FB5D2 /* DiskImageMounter.swift */,
|
||||||
39CF56232861CA85006FB5D2 /* DiskImageUnmounter.swift */,
|
39CF56232861CA85006FB5D2 /* DiskImageUnmounter.swift */,
|
||||||
3935F47D2864813B00760AB0 /* DownloadManager.swift */,
|
3935F47D2864813B00760AB0 /* DownloadManager.swift */,
|
||||||
|
39CA25E22941D8BB0030711E /* FileAttributesUpdater.swift */,
|
||||||
39CF56382862D75D006FB5D2 /* FileCreator.swift */,
|
39CF56382862D75D006FB5D2 /* FileCreator.swift */,
|
||||||
39CF56342862D4BF006FB5D2 /* FileCompressor.swift */,
|
39CF56342862D4BF006FB5D2 /* FileCompressor.swift */,
|
||||||
39CF56162861BE66006FB5D2 /* FileCopier.swift */,
|
39CF56162861BE66006FB5D2 /* FileCopier.swift */,
|
||||||
|
@ -803,6 +806,7 @@
|
||||||
390451D02856F63700E0B563 /* Installer.swift in Sources */,
|
390451D02856F63700E0B563 /* Installer.swift in Sources */,
|
||||||
3935F47628643AF000760AB0 /* UNNotificationAction+Extension.swift in Sources */,
|
3935F47628643AF000760AB0 /* UNNotificationAction+Extension.swift in Sources */,
|
||||||
39252AB3285C5D7700956C74 /* SettingsGeneralUpdatesView.swift in Sources */,
|
39252AB3285C5D7700956C74 /* SettingsGeneralUpdatesView.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 */,
|
||||||
390451CA2856F1D300E0B563 /* ScaledImage.swift in Sources */,
|
390451CA2856F1D300E0B563 /* ScaledImage.swift in Sources */,
|
||||||
|
|
36
Mist/Helpers/FileAttributesUpdater.swift
Normal file
36
Mist/Helpers/FileAttributesUpdater.swift
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// FileAttributesUpdater.swift
|
||||||
|
// Mist
|
||||||
|
//
|
||||||
|
// Created by Nindi Gill on 8/12/2022.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SecureXPC
|
||||||
|
|
||||||
|
/// Helper struct to update file / directory attributes
|
||||||
|
struct FileAttributesUpdater {
|
||||||
|
|
||||||
|
/// Update file / directory attributes at the provided URL.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - url: The URL of the file / directory to update.
|
||||||
|
/// - ownerAccountName: The username of the user that will be used to set the file / directory ownership.
|
||||||
|
///
|
||||||
|
/// - Throws: An `Error` if the command failed to execute.
|
||||||
|
static func update(url: URL, ownerAccountName: String) async throws {
|
||||||
|
|
||||||
|
guard FileManager.default.fileExists(atPath: url.path) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let arguments: [String] = [url.path, ownerAccountName]
|
||||||
|
let client: XPCClient = XPCClient.forMachService(named: .helperIdentifier)
|
||||||
|
let request: HelperToolCommandRequest = HelperToolCommandRequest(type: .fileAttributes, arguments: arguments, environment: [:])
|
||||||
|
let response: HelperToolCommandResponse = try await client.sendMessage(request, to: XPCRoute.commandRoute)
|
||||||
|
|
||||||
|
guard response.terminationStatus == 0 else {
|
||||||
|
throw MistError.invalidTerminationStatus(status: response.terminationStatus, string: response.standardError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import System
|
||||||
|
|
||||||
// swiftlint:disable file_length
|
// swiftlint:disable file_length
|
||||||
// swiftlint:disable:next type_body_length
|
// swiftlint:disable:next type_body_length
|
||||||
|
@ -231,6 +232,24 @@ class TaskManager: ObservableObject {
|
||||||
try await DirectoryCreator.create(cacheDirectoryURL, withIntermediateDirectories: true)
|
try await DirectoryCreator.create(cacheDirectoryURL, withIntermediateDirectories: true)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
} else {
|
||||||
|
let attributes: [FileAttributeKey: Any] = try FileManager.default.attributesOfItem(atPath: cacheDirectoryURL.path)
|
||||||
|
|
||||||
|
guard let posixPermissions: NSNumber = attributes[.posixPermissions] as? NSNumber,
|
||||||
|
let ownerAccountName: String = attributes[.ownerAccountName] as? String,
|
||||||
|
let groupOwnerAccountName: String = attributes[.groupOwnerAccountName] as? String else {
|
||||||
|
throw MistError.missingFileAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
let filePermissions: FilePermissions = FilePermissions(rawValue: CModeT(posixPermissions.int16Value))
|
||||||
|
|
||||||
|
if filePermissions != [.ownerReadWriteExecute, .groupReadExecute, .otherReadExecute] || ownerAccountName != NSUserName() || groupOwnerAccountName != "staff" {
|
||||||
|
tasks += [
|
||||||
|
MistTask(type: .configure, description: "cache directory") {
|
||||||
|
try await FileAttributesUpdater.update(url: cacheDirectoryURL, ownerAccountName: ownerAccountName)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for package in installer.allDownloads {
|
for package in installer.allDownloads {
|
||||||
|
|
|
@ -10,4 +10,5 @@ import Foundation
|
||||||
enum DownloadAlertType: String {
|
enum DownloadAlertType: String {
|
||||||
case compatibility = "Compatiblity"
|
case compatibility = "Compatiblity"
|
||||||
case helperTool = "Helper Tool"
|
case helperTool = "Helper Tool"
|
||||||
|
case cacheDirectory = "Cache Directory"
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@ struct Firmware: Decodable, Hashable, Identifiable {
|
||||||
|
|
||||||
static var example: Firmware {
|
static var example: Firmware {
|
||||||
Firmware(
|
Firmware(
|
||||||
version: "12.4",
|
version: "13.0",
|
||||||
build: "21F79",
|
build: "22A380",
|
||||||
shasum: "b5553b62da22e5fdbab2b56b6eb1fb74b58555ac",
|
shasum: "348f49da377d8c394672d1b2800d23452a1d6215",
|
||||||
size: 13_837_340_777,
|
size: 12_197_669_257,
|
||||||
url: "https://updates.cdn-apple.com/2022SpringFCS/fullrestores/012-06874/9CECE956-D945-45E2-93E9-4FFDC81BB49A/UniversalMac_12.4_21F79_Restore.ipsw",
|
url: "https://updates.cdn-apple.com/2022FallFCS/fullrestores/012-92188/2C38BCD1-2BFF-4A10-B358-94E8E28BE805/UniversalMac_13.0_22A380_Restore.ipsw",
|
||||||
date: "2022-05-16T18:23:48Z",
|
date: "2022-10-24T17:20:22Z",
|
||||||
signed: true,
|
signed: true,
|
||||||
compatible: true
|
compatible: true
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,15 +24,115 @@ struct Installer: Decodable, Hashable, Identifiable {
|
||||||
|
|
||||||
static var example: Installer {
|
static var example: Installer {
|
||||||
Installer(
|
Installer(
|
||||||
id: "012-06873",
|
id: "012-92138",
|
||||||
version: "12.4",
|
version: "13.0",
|
||||||
build: "21F79",
|
build: "22A380",
|
||||||
date: "2022-05-25",
|
date: "2022-10-25",
|
||||||
distributionURL: "https://swdist.apple.com/content/downloads/25/34/002-83506-A_0FVTHWXTXJ/9ipp8rhxtcyzjg9pdxekzznprkx48ssbo1/002-83506.English.dist",
|
distributionURL: "https://swdist.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/012-92138.English.dist",
|
||||||
distributionSize: 7_242,
|
distributionSize: 7_467,
|
||||||
packages: [],
|
packages: [
|
||||||
boardIDs: [],
|
Package(
|
||||||
deviceIDs: [],
|
url: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/MajorOSInfo.pkg",
|
||||||
|
size: 1_334_737,
|
||||||
|
integrityDataURL: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/MajorOSInfo.pkg.integrityDataV1",
|
||||||
|
integrityDataSize: 104
|
||||||
|
),
|
||||||
|
Package(
|
||||||
|
url: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/InstallAssistant.pkg",
|
||||||
|
size: 12_151_608_300,
|
||||||
|
integrityDataURL: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/InstallAssistant.pkg.integrityDataV1",
|
||||||
|
integrityDataSize: 41_792
|
||||||
|
),
|
||||||
|
Package(
|
||||||
|
url: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/BuildManifest.plist",
|
||||||
|
size: 3_355_762,
|
||||||
|
integrityDataURL: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/BuildManifest.plist.integrityDataV1",
|
||||||
|
integrityDataSize: 104
|
||||||
|
),
|
||||||
|
Package(
|
||||||
|
url: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/InstallInfo.plist",
|
||||||
|
size: 181,
|
||||||
|
integrityDataURL: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/InstallInfo.plist.integrityDataV1",
|
||||||
|
integrityDataSize: 104
|
||||||
|
),
|
||||||
|
Package(
|
||||||
|
url: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/UpdateBrain.zip",
|
||||||
|
size: 3_450_528,
|
||||||
|
integrityDataURL: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/UpdateBrain.zip.integrityDataV1",
|
||||||
|
integrityDataSize: 104
|
||||||
|
),
|
||||||
|
Package(
|
||||||
|
url: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/Info.plist",
|
||||||
|
size: 5_042,
|
||||||
|
integrityDataURL: "https://swcdn.apple.com/content/downloads/25/16/012-92138-A_KGGGN26YQB/d0kr042ixfvkboeft8qt2i3aclr5bx1e6p/Info.plist.integrityDataV1",
|
||||||
|
integrityDataSize: 104
|
||||||
|
)
|
||||||
|
],
|
||||||
|
boardIDs: [
|
||||||
|
"Mac-0CFF9C7C2B63DF8D",
|
||||||
|
"Mac-112818653D3AABFC",
|
||||||
|
"Mac-1E7E29AD0135F9BC",
|
||||||
|
"Mac-226CB3C6A851A671",
|
||||||
|
"Mac-27AD2F918AE68F61",
|
||||||
|
"Mac-4B682C642B45593E",
|
||||||
|
"Mac-53FDB3D8DB8CA971",
|
||||||
|
"Mac-551B86E5744E2388",
|
||||||
|
"Mac-5F9802EFE386AA28",
|
||||||
|
"Mac-63001698E7A34814",
|
||||||
|
"Mac-77F17D7DA9285301",
|
||||||
|
"Mac-7BA5B2D9E42DDD94",
|
||||||
|
"Mac-7BA5B2DFE22DDD8C",
|
||||||
|
"Mac-827FAC58A8FDFA22",
|
||||||
|
"Mac-827FB448E656EC26",
|
||||||
|
"Mac-937A206F2EE63C01",
|
||||||
|
"Mac-A61BADE1FDAD7B05",
|
||||||
|
"Mac-AA95B1DDAB278B95",
|
||||||
|
"Mac-AF89B6D9451A490B",
|
||||||
|
"Mac-B4831CEBD52A0C4C",
|
||||||
|
"Mac-BE088AF8C5EB4FA2",
|
||||||
|
"Mac-CAD6701F7CEA0921",
|
||||||
|
"Mac-CFF7D910A743CAAF",
|
||||||
|
"Mac-E1008331FDC96864",
|
||||||
|
"Mac-E7203C0F68AA0004",
|
||||||
|
"Mac-EE2EBD4B90B839A8"
|
||||||
|
],
|
||||||
|
deviceIDs: [
|
||||||
|
"J132AP",
|
||||||
|
"J137AP",
|
||||||
|
"J140AAP",
|
||||||
|
"J140KAP",
|
||||||
|
"J152FAP",
|
||||||
|
"J160AP",
|
||||||
|
"J174AP",
|
||||||
|
"J185AP",
|
||||||
|
"J185FAP",
|
||||||
|
"J213AP",
|
||||||
|
"J214AP",
|
||||||
|
"J214KAP",
|
||||||
|
"J215AP",
|
||||||
|
"J223AP",
|
||||||
|
"J230AP",
|
||||||
|
"J230KAP",
|
||||||
|
"J274AP",
|
||||||
|
"J293AP",
|
||||||
|
"J313AP",
|
||||||
|
"J314CAP",
|
||||||
|
"J314SAP",
|
||||||
|
"J316CAP",
|
||||||
|
"J316SAP",
|
||||||
|
"J375CAP",
|
||||||
|
"J375DAP",
|
||||||
|
"J413AP",
|
||||||
|
"J456AP",
|
||||||
|
"J457AP",
|
||||||
|
"J493AP",
|
||||||
|
"J680AP",
|
||||||
|
"J780AP",
|
||||||
|
"VMA2MACOSAP",
|
||||||
|
"VMM-X86_64",
|
||||||
|
"X589AMLUAP",
|
||||||
|
"X86LEGACYAP"
|
||||||
|
],
|
||||||
unsupportedModelIdentifiers: []
|
unsupportedModelIdentifiers: []
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ enum MistError: Error, Equatable {
|
||||||
case invalidTerminationStatus(status: Int32, string: String?)
|
case invalidTerminationStatus(status: Int32, string: String?)
|
||||||
case invalidURL(_ url: String)
|
case invalidURL(_ url: String)
|
||||||
case maximumRetriesReached
|
case maximumRetriesReached
|
||||||
|
case missingFileAttributes
|
||||||
case outputStreamBufferError
|
case outputStreamBufferError
|
||||||
case outputStreamWriteError
|
case outputStreamWriteError
|
||||||
case userCancelled
|
case userCancelled
|
||||||
|
@ -51,6 +52,8 @@ enum MistError: Error, Equatable {
|
||||||
return "Invalid URL: '\(url)'"
|
return "Invalid URL: '\(url)'"
|
||||||
case .maximumRetriesReached:
|
case .maximumRetriesReached:
|
||||||
return "Maximum number of retries reached"
|
return "Maximum number of retries reached"
|
||||||
|
case .missingFileAttributes:
|
||||||
|
return "Missing file attributes"
|
||||||
case .outputStreamBufferError:
|
case .outputStreamBufferError:
|
||||||
return "Output Stream Buffer Error"
|
return "Output Stream Buffer Error"
|
||||||
case .outputStreamWriteError:
|
case .outputStreamWriteError:
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import Blessed
|
import Blessed
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import System
|
||||||
|
|
||||||
struct ListRow: View {
|
struct ListRow: View {
|
||||||
var type: DownloadType
|
var type: DownloadType
|
||||||
|
@ -21,6 +22,8 @@ struct ListRow: View {
|
||||||
@ObservedObject var taskManager: TaskManager
|
@ObservedObject var taskManager: TaskManager
|
||||||
@State private var alertType: DownloadAlertType = .compatibility
|
@State private var alertType: DownloadAlertType = .compatibility
|
||||||
@State private var showAlert: Bool = false
|
@State private var showAlert: Bool = false
|
||||||
|
@AppStorage("cacheDownloads") private var cacheDownloads: Bool = false
|
||||||
|
@AppStorage("cacheDirectory") private var cacheDirectory: String = .cacheDirectory
|
||||||
private let length: CGFloat = 48
|
private let length: CGFloat = 48
|
||||||
private let spacing: CGFloat = 5
|
private let spacing: CGFloat = 5
|
||||||
private var compatibilityTitle: String {
|
private var compatibilityTitle: String {
|
||||||
|
@ -43,6 +46,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 cacheDirectoryTitle: String {
|
||||||
|
"Cache directory settings incorrect!"
|
||||||
|
}
|
||||||
|
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."
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
|
@ -83,7 +92,14 @@ struct ListRow: View {
|
||||||
return Alert(
|
return Alert(
|
||||||
title: Text(privilegedHelperToolTitle),
|
title: Text(privilegedHelperToolTitle),
|
||||||
message: Text(privilegedHelperToolMessage),
|
message: Text(privilegedHelperToolMessage),
|
||||||
primaryButton: .default(Text("Install...")) { install() },
|
primaryButton: .default(Text("Install...")) { installPrivilegedHelperTool() },
|
||||||
|
secondaryButton: .default(Text("Cancel"))
|
||||||
|
)
|
||||||
|
case .cacheDirectory:
|
||||||
|
return Alert(
|
||||||
|
title: Text(cacheDirectoryTitle),
|
||||||
|
message: Text(cacheDirectoryMessage),
|
||||||
|
primaryButton: .default(Text("Repair...")) { Task { try await repairCacheDirectoryOwnershipAndPermissions() } },
|
||||||
secondaryButton: .default(Text("Cancel"))
|
secondaryButton: .default(Text("Cancel"))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -103,12 +119,47 @@ struct ListRow: View {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cacheDownloads {
|
||||||
|
|
||||||
|
do {
|
||||||
|
let attributes: [FileAttributeKey: Any] = try FileManager.default.attributesOfItem(atPath: cacheDirectory)
|
||||||
|
|
||||||
|
guard let posixPermissions: NSNumber = attributes[.posixPermissions] as? NSNumber else {
|
||||||
|
alertType = .cacheDirectory
|
||||||
|
showAlert = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let filePermissions: FilePermissions = FilePermissions(rawValue: CModeT(posixPermissions.int16Value))
|
||||||
|
|
||||||
|
guard filePermissions == [.ownerReadWriteExecute, .groupReadExecute, .otherReadExecute],
|
||||||
|
let ownerAccountName: String = attributes[.ownerAccountName] as? String,
|
||||||
|
ownerAccountName == NSUserName(),
|
||||||
|
let groupOwnerAccountName: String = attributes[.groupOwnerAccountName] as? String,
|
||||||
|
groupOwnerAccountName == "staff" else {
|
||||||
|
alertType = .cacheDirectory
|
||||||
|
showAlert = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
alertType = .cacheDirectory
|
||||||
|
showAlert = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
showPanel = true
|
showPanel = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private func install() {
|
private func installPrivilegedHelperTool() {
|
||||||
try? PrivilegedHelperManager.shared.authorizeAndBless()
|
try? PrivilegedHelperManager.shared.authorizeAndBless()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func repairCacheDirectoryOwnershipAndPermissions() async throws {
|
||||||
|
let url: URL = URL(fileURLWithPath: cacheDirectory)
|
||||||
|
let ownerAccountName: String = NSUserName()
|
||||||
|
try await FileAttributesUpdater.update(url: url, ownerAccountName: ownerAccountName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ListRow_Previews: PreviewProvider {
|
struct ListRow_Previews: PreviewProvider {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>BuildHash</key>
|
<key>BuildHash</key>
|
||||||
<string>631381272a839c41efa70afa56e8d6e05a0bdbc167d07ecae792ed338ac0a353</string>
|
<string>977665398f7c4fc4f84fda51c877a98d25ab4a8ed94c7c532dc7070c8e1c845d</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.ninxsoft.mist.helper</string>
|
<string>com.ninxsoft.mist.helper</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
|
|
@ -25,7 +25,7 @@ struct HelperToolCommandRunner {
|
||||||
case .remove:
|
case .remove:
|
||||||
|
|
||||||
guard let path: String = request.arguments.first else {
|
guard let path: String = request.arguments.first else {
|
||||||
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: "Invalid URL")
|
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: "Invalid URL: \(request.arguments)")
|
||||||
}
|
}
|
||||||
|
|
||||||
guard FileManager.default.fileExists(atPath: path) else {
|
guard FileManager.default.fileExists(atPath: path) else {
|
||||||
|
@ -38,6 +38,25 @@ struct HelperToolCommandRunner {
|
||||||
} catch {
|
} catch {
|
||||||
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: error.localizedDescription)
|
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: error.localizedDescription)
|
||||||
}
|
}
|
||||||
|
case .fileAttributes:
|
||||||
|
|
||||||
|
guard let path: String = request.arguments.first,
|
||||||
|
let ownerAccountName: String = request.arguments.last else {
|
||||||
|
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: "Invalid attributes: \(request.arguments)")
|
||||||
|
}
|
||||||
|
|
||||||
|
let attributes: [FileAttributeKey: Any] = [
|
||||||
|
.posixPermissions: 0o755,
|
||||||
|
.ownerAccountName: ownerAccountName,
|
||||||
|
.groupOwnerAccountName: "staff"
|
||||||
|
]
|
||||||
|
|
||||||
|
do {
|
||||||
|
try FileManager.default.setAttributes(attributes, ofItemAtPath: path)
|
||||||
|
return HelperToolCommandResponse(terminationStatus: 0, standardOutput: nil, standardError: nil)
|
||||||
|
} catch {
|
||||||
|
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: error.localizedDescription)
|
||||||
|
}
|
||||||
case .kill:
|
case .kill:
|
||||||
ShellExecutor.shared.terminate()
|
ShellExecutor.shared.terminate()
|
||||||
return HelperToolCommandResponse(terminationStatus: 0, standardOutput: nil, standardError: nil)
|
return HelperToolCommandResponse(terminationStatus: 0, standardOutput: nil, standardError: nil)
|
||||||
|
|
|
@ -11,6 +11,8 @@ enum HelperToolCommandType: String, Codable {
|
||||||
// swiftlint:disable:next redundant_string_enum_value
|
// swiftlint:disable:next redundant_string_enum_value
|
||||||
case remove = "remove"
|
case remove = "remove"
|
||||||
// swiftlint:disable:next redundant_string_enum_value
|
// swiftlint:disable:next redundant_string_enum_value
|
||||||
|
case fileAttributes = "fileAttributes"
|
||||||
|
// swiftlint:disable:next redundant_string_enum_value
|
||||||
case installer = "installer"
|
case installer = "installer"
|
||||||
// swiftlint:disable:next redundant_string_enum_value
|
// swiftlint:disable:next redundant_string_enum_value
|
||||||
case createinstallmedia = "createinstallmedia"
|
case createinstallmedia = "createinstallmedia"
|
||||||
|
|
|
@ -59,8 +59,6 @@ class ShellExecutor: NSObject {
|
||||||
return (terminationStatus: terminationStatus, standardOutput: standardOutput, standardError: (standardError ?? "").isEmpty ? nil : standardError)
|
return (terminationStatus: terminationStatus, standardOutput: standardOutput, standardError: (standardError ?? "").isEmpty ? nil : standardError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:enable large_tuple
|
|
||||||
|
|
||||||
func terminate() {
|
func terminate() {
|
||||||
|
|
||||||
guard process.isRunning else {
|
guard process.isRunning else {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue