From a5fcffd71fb5352bfc0e6ba9a2fcf8f5fdc4a927 Mon Sep 17 00:00:00 2001 From: Nindi Gill Date: Sun, 29 Oct 2023 23:36:09 +1100 Subject: [PATCH 1/4] Add support for legacy ISOs on Apple Silicon --- Mist/Helpers/Codesigner.swift | 15 +++++++++++++++ Mist/Helpers/TaskManager.swift | 13 +++++++++++++ Mist/Views/List/InstallerExportView.swift | 21 +-------------------- Mist/Views/List/ListRowInstaller.swift | 3 +-- Mist/Views/Settings/SettingsISOsView.swift | 2 +- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/Mist/Helpers/Codesigner.swift b/Mist/Helpers/Codesigner.swift index f6b3227..880a025 100644 --- a/Mist/Helpers/Codesigner.swift +++ b/Mist/Helpers/Codesigner.swift @@ -25,4 +25,19 @@ struct Codesigner { throw MistError.invalidTerminationStatus(status: response.terminationStatus, output: response.standardOutput, error: response.standardError) } } + + /// Ad-hoc sign all files within a directory (or app bundle). + /// + /// - Parameters: + /// - url: The URL of the directory to ad-hoc sign. + /// + /// - Throws: A `MistError` if the command failed to execute. + static func adhocSign(_ url: URL) async throws { + let arguments: [String] = ["find", url.path, "-type", "f", "-exec", "codesign", "--sign", "-", "--force", "{}", ";"] + let response: HelperToolCommandResponse = try ShellExecutor.shared.execute(arguments) + + guard response.terminationStatus == 0 else { + throw MistError.invalidTerminationStatus(status: response.terminationStatus, output: response.standardOutput, error: response.standardError) + } + } } diff --git a/Mist/Helpers/TaskManager.swift b/Mist/Helpers/TaskManager.swift index 2d2ad9b..e287f84 100644 --- a/Mist/Helpers/TaskManager.swift +++ b/Mist/Helpers/TaskManager.swift @@ -426,6 +426,7 @@ class TaskManager: ObservableObject { return tasks } + // swiftlint:disable:next function_body_length private static func isoTasks(for installer: Installer, filename: String, destination destinationURL: URL, temporaryDirectory temporaryDirectoryURL: URL) -> [MistTask] { let temporaryImageURL: URL = temporaryDirectoryURL.appendingPathComponent("\(installer.id).dmg") @@ -443,6 +444,12 @@ class TaskManager: ObservableObject { }, MistTask(type: .create, description: "macOS Installer in temporary Disk Image") { + // Workaround to make OS X Yosemite 10.10 to macOS Catalina 10.15 createinstallmedia work on Apple Silicon + if let architecture: Architecture = Hardware.architecture, + architecture == .appleSilicon && !installer.bigSurOrNewer { + try await Codesigner.adhocSign(installer.temporaryInstallerURL) + } + // Workaround to make macOS Sierra 10.12 createinstallmedia work if installer.version.hasPrefix("10.12") { let infoPlistURL: URL = installer.temporaryInstallerURL.appendingPathComponent("Contents/Info.plist") @@ -533,6 +540,12 @@ class TaskManager: ObservableObject { let tasks: [MistTask] = [ MistTask(type: .create, description: "Bootable Installer") { + // Workaround to make OS X Yosemite 10.10 to macOS Catalina 10.15 createinstallmedia work on Apple Silicon + if let architecture: Architecture = Hardware.architecture, + architecture == .appleSilicon && !installer.bigSurOrNewer { + try await Codesigner.adhocSign(installer.temporaryInstallerURL) + } + // Workaround to make macOS Sierra 10.12 createinstallmedia work if installer.version.hasPrefix("10.12") { let infoPlistURL: URL = installer.temporaryInstallerURL.appendingPathComponent("Contents/Info.plist") diff --git a/Mist/Views/List/InstallerExportView.swift b/Mist/Views/List/InstallerExportView.swift index aa32c11..15b0a9f 100644 --- a/Mist/Views/List/InstallerExportView.swift +++ b/Mist/Views/List/InstallerExportView.swift @@ -18,16 +18,6 @@ struct InstallerExportView: View { private var exportPackage: Bool = false var installer: Installer @Binding var exports: [InstallerExportType] - private var isoCompatible: Bool { - guard let architecture: Architecture = Hardware.architecture else { - return false - } - - return architecture == .intel || (architecture == .appleSilicon && installer.bigSurOrNewer) - } - private var compatibilityMessage: String { - "**Note:** ISOs are unavailable for building **macOS Catalina 10.15 and older** on [Apple Silicon Macs](https://support.apple.com/en-us/HT211814)." - } var body: some View { VStack { @@ -40,16 +30,11 @@ struct InstallerExportView: View { InstallerExportViewItem(exportType: .diskImage, selected: $exportDiskImage) .disabled(exports.count == 1 && exportDiskImage) InstallerExportViewItem(exportType: .iso, selected: $exportISO) - .disabled(isoCompatible ? exports.count == 1 && exportISO : true) - .opacity(isoCompatible ? 1 : 0.5) + .disabled(exports.count == 1 && exportISO) InstallerExportViewItem(exportType: .package, selected: $exportPackage) .disabled(exports.count == 1 && exportPackage) Spacer() } - if !isoCompatible { - Text(.init(compatibilityMessage)) - .padding(.top) - } } .padding() .onChange(of: exportApplication) { _ in @@ -73,10 +58,6 @@ struct InstallerExportView: View { var exports: [InstallerExportType] = [] - if !isoCompatible && exportISO { - exportISO = false - } - if !exportApplication && !exportDiskImage && !exportISO && !exportPackage { exportApplication = true } diff --git a/Mist/Views/List/ListRowInstaller.swift b/Mist/Views/List/ListRowInstaller.swift index 9be0694..24e9074 100644 --- a/Mist/Views/List/ListRowInstaller.swift +++ b/Mist/Views/List/ListRowInstaller.swift @@ -91,8 +91,7 @@ struct ListRowInstaller: View { } .help("Download and export macOS Installer") .buttonStyle(.mistAction) - if let architecture: Architecture = Hardware.architecture, - (architecture == .appleSilicon && installer.bigSurOrNewer) || (architecture == .intel && installer.mavericksOrNewer) { + if installer.mavericksOrNewer { Button { pressButton(.volumeSelection) } label: { diff --git a/Mist/Views/Settings/SettingsISOsView.swift b/Mist/Views/Settings/SettingsISOsView.swift index b05209a..4efebb2 100644 --- a/Mist/Views/Settings/SettingsISOsView.swift +++ b/Mist/Views/Settings/SettingsISOsView.swift @@ -13,7 +13,7 @@ struct SettingsISOsView: View { private let imageName: String = "ISO" private let title: String = "ISOs" // swiftlint:disable:next line_length - private let description: String = "ISOs are Bootable macOS Installer Disk Images that can be restored on external USB drives, or used with virtualization software (ie. [Parallels Desktop](https://www.parallels.com/au/products/desktop/), [UTM](https://mac.getutm.app), [VMware Fusion](https://www.vmware.com/au/products/fusion.html), [VirtualBox](https://www.virtualbox.org)).\n\n**Note:** ISOs are unavailable for building **macOS Catalina 10.15 and older** on [Apple Silicon Macs](https://support.apple.com/en-us/HT211814)." + private let description: String = "ISOs are Bootable macOS Installer Disk Images that can be restored on external USB drives, or used with virtualization software (ie. [Parallels Desktop](https://www.parallels.com/au/products/desktop/), [UTM](https://mac.getutm.app), [VMware Fusion](https://www.vmware.com/au/products/fusion.html), [VirtualBox](https://www.virtualbox.org))." var body: some View { VStack(alignment: .leading) { From 2cc427ee4363f14699ee5b734a0bd51262456bc3 Mon Sep 17 00:00:00 2001 From: Nindi Gill Date: Sun, 25 Feb 2024 17:24:28 +1100 Subject: [PATCH 2/4] Update InstallerExportView.swift --- Mist/Views/List/InstallerExportView.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Mist/Views/List/InstallerExportView.swift b/Mist/Views/List/InstallerExportView.swift index 2e7c961..0ddcdfd 100644 --- a/Mist/Views/List/InstallerExportView.swift +++ b/Mist/Views/List/InstallerExportView.swift @@ -57,10 +57,6 @@ struct InstallerExportView: View { private func updateExports() { var exports: [InstallerExportType] = [] - if !isoCompatible, exportISO { - exportISO = false - } - if !exportApplication, !exportDiskImage, !exportISO, !exportPackage { exportApplication = true } From ab732e9fb25270fd83ea688f882e953dcbb6b9f1 Mon Sep 17 00:00:00 2001 From: Nindi Gill Date: Sun, 25 Feb 2024 17:25:19 +1100 Subject: [PATCH 3/4] Fix SwiftLint warning --- Mist/Helpers/TaskManager.swift | 10 ++++++---- Mist/Views/List/ListRowInstaller.swift | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Mist/Helpers/TaskManager.swift b/Mist/Helpers/TaskManager.swift index 1c3c886..955c72e 100644 --- a/Mist/Helpers/TaskManager.swift +++ b/Mist/Helpers/TaskManager.swift @@ -464,8 +464,9 @@ class TaskManager: ObservableObject { }, MistTask(type: .create, description: "macOS Installer in temporary Disk Image") { // Workaround to make OS X Yosemite 10.10 to macOS Catalina 10.15 createinstallmedia work on Apple Silicon - if let architecture: Architecture = Hardware.architecture, - architecture == .appleSilicon && !installer.bigSurOrNewer { + if + let architecture: Architecture = Hardware.architecture, + architecture == .appleSilicon, !installer.bigSurOrNewer { try await Codesigner.adhocSign(installer.temporaryInstallerURL) } @@ -570,8 +571,9 @@ class TaskManager: ObservableObject { let tasks: [MistTask] = [ MistTask(type: .create, description: "Bootable Installer") { // Workaround to make OS X Yosemite 10.10 to macOS Catalina 10.15 createinstallmedia work on Apple Silicon - if let architecture: Architecture = Hardware.architecture, - architecture == .appleSilicon && !installer.bigSurOrNewer { + if + let architecture: Architecture = Hardware.architecture, + architecture == .appleSilicon, !installer.bigSurOrNewer { try await Codesigner.adhocSign(installer.temporaryInstallerURL) } diff --git a/Mist/Views/List/ListRowInstaller.swift b/Mist/Views/List/ListRowInstaller.swift index c3c974d..7aab812 100644 --- a/Mist/Views/List/ListRowInstaller.swift +++ b/Mist/Views/List/ListRowInstaller.swift @@ -73,7 +73,6 @@ struct ListRowInstaller: View { } var body: some View { - // swiftlint:disable:next closure_body_length HStack { ListRowDetail( imageName: installer.imageName, From 281083aab8da3206ce6c46bb54194231dd05184a Mon Sep 17 00:00:00 2001 From: Nindi Gill Date: Sun, 25 Feb 2024 21:50:39 +1100 Subject: [PATCH 4/4] Adhoc codesign a file instead of a directory recursively --- Mist/Helpers/Codesigner.swift | 6 +++--- Mist/Helpers/TaskManager.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mist/Helpers/Codesigner.swift b/Mist/Helpers/Codesigner.swift index b66f7ac..5e666c4 100644 --- a/Mist/Helpers/Codesigner.swift +++ b/Mist/Helpers/Codesigner.swift @@ -25,14 +25,14 @@ enum Codesigner { } } - /// Ad-hoc sign all files within a directory (or app bundle). + /// Ad-hoc signs the file at the provided URL. /// /// - Parameters: - /// - url: The URL of the directory to ad-hoc sign. + /// - url: The URL of the file to ad-hoc sign. /// /// - Throws: A `MistError` if the command failed to execute. static func adhocSign(_ url: URL) async throws { - let arguments: [String] = ["find", url.path, "-type", "f", "-exec", "codesign", "--sign", "-", "--force", "{}", ";"] + let arguments: [String] = ["codesign", "--sign", "-", "--force", url.path] let response: HelperToolCommandResponse = try ShellExecutor.shared.execute(arguments) guard response.terminationStatus == 0 else { diff --git a/Mist/Helpers/TaskManager.swift b/Mist/Helpers/TaskManager.swift index 955c72e..0fde8ae 100644 --- a/Mist/Helpers/TaskManager.swift +++ b/Mist/Helpers/TaskManager.swift @@ -467,7 +467,7 @@ class TaskManager: ObservableObject { if let architecture: Architecture = Hardware.architecture, architecture == .appleSilicon, !installer.bigSurOrNewer { - try await Codesigner.adhocSign(installer.temporaryInstallerURL) + try await Codesigner.adhocSign(createInstallMediaURL) } // Workaround to make macOS Sierra 10.12 createinstallmedia work @@ -574,7 +574,7 @@ class TaskManager: ObservableObject { if let architecture: Architecture = Hardware.architecture, architecture == .appleSilicon, !installer.bigSurOrNewer { - try await Codesigner.adhocSign(installer.temporaryInstallerURL) + try await Codesigner.adhocSign(createInstallMediaURL) } // Workaround to make macOS Sierra 10.12 createinstallmedia work