diff --git a/AltStore/LaunchViewController.swift b/AltStore/LaunchViewController.swift index 195dd2bf..d3fde636 100644 --- a/AltStore/LaunchViewController.swift +++ b/AltStore/LaunchViewController.swift @@ -10,6 +10,8 @@ import UIKit import Roxas import minimuxer import WidgetKit + +import AltSign import AltStoreCore import UniformTypeIdentifiers @@ -70,7 +72,9 @@ final class LaunchViewController: UIViewController, UIDocumentPickerDelegate { } #if !targetEnvironment(simulator) - guard let pf = PairingFileManager.shared.fetchPairingFile(presentingVC: self) else { + + detectAndImportAccountFile() + guard let pf = fetchPairingFile() else { displayError("Device pairing file not found.") return } @@ -102,6 +106,11 @@ final class LaunchViewController: UIViewController, UIDocumentPickerDelegate { func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { let url = urls[0] let isSecuredURL = url.startAccessingSecurityScopedResource() == true + defer { + if (isSecuredURL) { + url.stopAccessingSecurityScopedResource() + } + } do { let data = try Data(contentsOf: url) @@ -114,14 +123,68 @@ final class LaunchViewController: UIViewController, UIDocumentPickerDelegate { } catch { displayError("Unable to read pairing file") } - - if isSecuredURL { url.stopAccessingSecurityScopedResource() } - controller.dismiss(animated: true) + + controller.dismiss(animated: true, completion: nil) } func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { displayError("Choosing a pairing file was cancelled. Please re-open the app and try again.") } + + func start_minimuxer_threads(_ pairing_file: String) { + target_minimuxer_address() + let documentsDirectory = FileManager.default.documentsDirectory.absoluteString + do { + // enable minimuxer console logging only if enabled in settings + let isMinimuxerConsoleLoggingEnabled = UserDefaults.standard.isMinimuxerConsoleLoggingEnabled + try minimuxer.startWithLogger(pairing_file, documentsDirectory, isMinimuxerConsoleLoggingEnabled) + } catch { + try! FileManager.default.removeItem(at: FileManager.default.documentsDirectory.appendingPathComponent("\(pairingFileName)")) + displayError("minimuxer failed to start, please restart SideStore. \((error as? LocalizedError)?.failureReason ?? "UNKNOWN ERROR!!!!!! REPORT TO GITHUB ISSUES!")") + } + start_auto_mounter(documentsDirectory) + // Create destinationViewController now so view controllers can register for receiving Notifications. + self.destinationViewController = self.storyboard!.instantiateViewController(withIdentifier: "tabBarController") as? TabBarController + } + + func importAccountAtFile(_ file: URL, remove: Bool = false) { + _ = file.startAccessingSecurityScopedResource() + defer { file.stopAccessingSecurityScopedResource() } + guard let accountD = try? Data(contentsOf: file) else { + let toastView = ToastView(text: NSLocalizedString("Could not read data from file!", comment: ""), detailText: "\(file)") + return toastView.show(in: self) + } + guard let account = try? Foundation.JSONDecoder().decode(ImportedAccount.self, from: accountD) else { + let toastView = ToastView(text: NSLocalizedString("Could not parse data from file!", comment: ""), detailText: "\(file)") + return toastView.show(in: self) + } + print("We want to import this account probably: \(account)") + if remove { + try? FileManager.default.removeItem(at: file) + } + Keychain.shared.appleIDEmailAddress = account.email + Keychain.shared.appleIDPassword = account.password + Keychain.shared.adiPb = account.adiPB + Keychain.shared.identifier = account.local_user + if let altCert = ALTCertificate(p12Data: account.cert, password: account.certpass) { + Keychain.shared.signingCertificate = altCert.encryptedP12Data(withPassword: "")! + Keychain.shared.signingCertificatePassword = account.certpass + let toastView = ToastView(text: NSLocalizedString("Successfully imported '\(account.email)'!", comment: ""), detailText: "SideStore should be fully operational!") + return toastView.show(in: self) + } else { + let toastView = ToastView(text: NSLocalizedString("Failed to import account certificate!", comment: ""), detailText: "Failed to create ALTCertificate. Check if the password is correct. Still imported account/adi.pb details!") + return toastView.show(in: self) + } + } + + func detectAndImportAccountFile() { + let accountFileURL = FileManager.default.documentsDirectory.appendingPathComponent("Account.sideconf") + #if !DEBUG + importAccountAtFile(accountFileURL, remove: true) + #else + importAccountAtFile(accountFileURL) + #endif + } } extension LaunchViewController { diff --git a/AltStore/Settings/SettingsViewController.swift b/AltStore/Settings/SettingsViewController.swift index f4f16c05..eeaa8657 100644 --- a/AltStore/Settings/SettingsViewController.swift +++ b/AltStore/Settings/SettingsViewController.swift @@ -261,28 +261,34 @@ final class SettingsViewController: UITableViewController } func importAccountAtFile(_ file: URL, remove: Bool = false) { - if let accountData = try? Data(contentsOf: file), - let account = try? Foundation.JSONDecoder().decode(ImportedAccount.self, from: accountData) { - print("We want to import this account probably: \(account)") - if remove { - try? FileManager.default.removeItem(at: file) - } - Keychain.shared.appleIDEmailAddress = account.email - Keychain.shared.appleIDPassword = account.password - Keychain.shared.adiPb = account.adiPB - Keychain.shared.adiSerial = account.serial - Keychain.shared.identifier = account.local_user - signIn() - update() - if let altCert = ALTCertificate(p12Data: account.cert, password: account.certpass) { - Keychain.shared.signingCertificate = altCert.encryptedP12Data(withPassword: "")! - Keychain.shared.signingCertificatePassword = account.certpass - let toastView = ToastView(text: NSLocalizedString("Successfully imported '\(account.email)'!", comment: ""), detailText: "SideStore should be fully operational!") - return toastView.show(in: self) - } else { - let toastView = ToastView(text: NSLocalizedString("Failed to import account certificate!", comment: ""), detailText: "Failed to create ALTCertificate. Check if the password is correct. Still imported account/adi.pb details!") - return toastView.show(in: self) - } + _ = file.startAccessingSecurityScopedResource() + defer { file.stopAccessingSecurityScopedResource() } + guard let accountD = try? Data(contentsOf: file) else { + let toastView = ToastView(text: NSLocalizedString("Could not read data from file!", comment: ""), detailText: "\(file)") + return toastView.show(in: self) + } + guard let account = try? Foundation.JSONDecoder().decode(ImportedAccount.self, from: accountD) else { + let toastView = ToastView(text: NSLocalizedString("Could not parse data from file!", comment: ""), detailText: "\(file)") + return toastView.show(in: self) + } + print("We want to import this account probably: \(account)") + if remove { + try? FileManager.default.removeItem(at: file) + } + Keychain.shared.appleIDEmailAddress = account.email + Keychain.shared.appleIDPassword = account.password + Keychain.shared.adiPb = account.adiPB + Keychain.shared.identifier = account.local_user + signIn() + update() + if let altCert = ALTCertificate(p12Data: account.cert, password: account.certpass) { + Keychain.shared.signingCertificate = altCert.encryptedP12Data(withPassword: "")! + Keychain.shared.signingCertificatePassword = account.certpass + let toastView = ToastView(text: NSLocalizedString("Successfully imported '\(account.email)'!", comment: ""), detailText: "SideStore should be fully operational!") + return toastView.show(in: self) + } else { + let toastView = ToastView(text: NSLocalizedString("Failed to import account certificate!", comment: ""), detailText: "Failed to create ALTCertificate. Check if the password is correct. Still imported account/adi.pb details!") + return toastView.show(in: self) } } @@ -300,7 +306,6 @@ final class SettingsViewController: UITableViewController let password = Keychain.shared.appleIDPassword, let cert = Keychain.shared.signingCertificate, let identifier = Keychain.shared.identifier, - let adiSerial = Keychain.shared.adiSerial, let adiPB = Keychain.shared.adiPb else { #if DEBUG print(Keychain.shared.appleIDEmailAddress ?? "Empty email") @@ -308,17 +313,16 @@ final class SettingsViewController: UITableViewController print(Keychain.shared.signingCertificate ?? "Empty cert") print(Keychain.shared.identifier ?? "Empty identifier") print(Keychain.shared.adiPb ?? "Empty adiPb") - print(Keychain.shared.adiSerial ?? "Empty adiSerial") #endif return nil } - return ImportedAccount(email: email, password: password, cert: cert, certpass: certpass, local_user: identifier, serial: adiSerial, adiPB: adiPB) + return ImportedAccount(email: email, password: password, cert: cert, certpass: certpass, local_user: identifier, adiPB: adiPB) } func showExportAccount() { Task { - let password = await withUnsafeContinuation { (c: UnsafeContinuation) in + guard let password = await withUnsafeContinuation({ (c: UnsafeContinuation) in let alertController = UIAlertController(title: NSLocalizedString("Please enter the password for the certificate.", comment: ""), message: nil, preferredStyle: .alert) alertController.addTextField { (textField) in @@ -338,19 +342,16 @@ final class SettingsViewController: UITableViewController }) self.present(alertController, animated: true) - } - - guard let password else { + }) else { return } guard let account = exportAccount(password) else { let toastView = ToastView(text: NSLocalizedString("Failed to export account!", comment: ""), detailText: "Account not found.") - toastView.show(in: self) - return + return toastView.show(in: self) } - guard let accountData = try? Foundation.JSONEncoder().encode(account).base64EncodedData() else { + guard let accountData = try? Foundation.JSONEncoder().encode(account) else { let toastView = ToastView(text: NSLocalizedString("Failed to export account data!", comment: ""), detailText: "Account malformed.") toastView.show(in: self) return @@ -1364,15 +1365,25 @@ extension SettingsViewController guard let confUrl else { return } - _ = confUrl.startAccessingSecurityScopedResource() - defer { confUrl.stopAccessingSecurityScopedResource() } importAccountAtFile(confUrl) } case .importCert: + let importVc = UIDocumentPickerViewController(forOpeningContentTypes: [UTType(filenameExtension: "p12")!], asCopy: false) + ImportExport.documentPickerHandler = DocumentPickerHandler { url in + guard let url else { + return + } + importVc.delegate = ImportExport.documentPickerHandler + self.present(importVc, animated: true) + _ = url.startAccessingSecurityScopedResource() + defer { url.stopAccessingSecurityScopedResource() } + } Task { let certUrl = await withUnsafeContinuation { c in let importVc = UIDocumentPickerViewController(forOpeningContentTypes: [UTType(filenameExtension: "p12")!], asCopy: false) ImportExport.documentPickerHandler = DocumentPickerHandler { url in + _ = url?.startAccessingSecurityScopedResource() + defer { url?.stopAccessingSecurityScopedResource() } c.resume(returning: url) } importVc.delegate = ImportExport.documentPickerHandler diff --git a/AltStore/Types/ImportedAccount.swift b/AltStore/Types/ImportedAccount.swift index c0e16060..ff47a48f 100644 --- a/AltStore/Types/ImportedAccount.swift +++ b/AltStore/Types/ImportedAccount.swift @@ -14,6 +14,5 @@ struct ImportedAccount: Codable { let cert: Data let certpass: String let local_user: String - let serial: String let adiPB: String } diff --git a/AltStoreCore/Components/Keychain.swift b/AltStoreCore/Components/Keychain.swift index b6543582..efc2808d 100644 --- a/AltStoreCore/Components/Keychain.swift +++ b/AltStoreCore/Components/Keychain.swift @@ -80,9 +80,6 @@ public class Keychain @KeychainItem(key: "identifier") public var identifier: String? - @KeychainItem(key: "adiSerial") - public var adiSerial: String? - @KeychainItem(key: "adiPb") public var adiPb: String?