Files
SideStore/SideStoreApp/Sources/SideDaemon/AppManager.swift

117 lines
5.2 KiB
Swift
Raw Normal View History

//
// AppManager.swift
// AltDaemon
//
// Created by Riley Testut on 6/1/20.
// Copyright © 2020 Riley Testut. All rights reserved.
//
import Foundation
import AltSign
2023-03-01 00:48:36 -05:00
private extension URL {
static let profilesDirectoryURL = URL(fileURLWithPath: "/var/MobileDevice/ProvisioningProfiles", isDirectory: true)
}
2023-03-01 00:48:36 -05:00
private extension CFNotificationName {
static let updatedProvisioningProfiles = CFNotificationName("MISProvisioningProfileRemoved" as CFString)
}
2023-03-01 00:48:36 -05:00
struct AppManager {
static let shared = AppManager()
2023-03-01 00:48:36 -05:00
private let appQueue = DispatchQueue(label: "com.rileytestut.AltDaemon.appQueue", qos: .userInitiated)
private let profilesQueue = OperationQueue()
2023-03-01 00:48:36 -05:00
private let fileCoordinator = NSFileCoordinator()
2023-03-01 00:48:36 -05:00
private init() {
profilesQueue.name = "com.rileytestut.AltDaemon.profilesQueue"
profilesQueue.qualityOfService = .userInitiated
}
2023-03-01 00:48:36 -05:00
func installApp(at fileURL: URL, bundleIdentifier: String, activeProfiles _: Set<String>?, completionHandler: @escaping (Result<Void, Error>) -> Void) {
appQueue.async {
let lsApplicationWorkspace = unsafeBitCast(NSClassFromString("LSApplicationWorkspace")!, to: LSApplicationWorkspace.Type.self)
2023-03-01 00:48:36 -05:00
let options = ["CFBundleIdentifier": bundleIdentifier, "AllowInstallLocalProvisioned": NSNumber(value: true)] as [String: Any]
let result = Result { try lsApplicationWorkspace.default.installApplication(fileURL, withOptions: options) }
2023-03-01 00:48:36 -05:00
completionHandler(result)
}
}
2023-03-01 00:48:36 -05:00
func removeApp(forBundleIdentifier bundleIdentifier: String, completionHandler: @escaping (Result<Void, Error>) -> Void) {
appQueue.async {
let lsApplicationWorkspace = unsafeBitCast(NSClassFromString("LSApplicationWorkspace")!, to: LSApplicationWorkspace.Type.self)
lsApplicationWorkspace.default.uninstallApplication(bundleIdentifier, withOptions: nil)
2023-03-01 00:48:36 -05:00
completionHandler(.success(()))
}
}
2023-03-01 00:48:36 -05:00
func install(_ profiles: Set<ALTProvisioningProfile>, activeProfiles: Set<String>?, completionHandler: @escaping (Result<Void, Error>) -> Void) {
let intent = NSFileAccessIntent.writingIntent(with: .profilesDirectoryURL, options: [])
2023-03-01 00:48:36 -05:00
fileCoordinator.coordinate(with: [intent], queue: profilesQueue) { error in
do {
if let error = error {
throw error
}
2023-03-01 00:48:36 -05:00
let installingBundleIDs = Set(profiles.map(\.bundleIdentifier))
2023-03-01 00:48:36 -05:00
let profileURLs = try FileManager.default.contentsOfDirectory(at: intent.url, includingPropertiesForKeys: nil, options: [])
2023-03-01 00:48:36 -05:00
// Remove all inactive profiles (if active profiles are provided), and the previous profiles.
2023-03-01 00:48:36 -05:00
for fileURL in profileURLs {
// Use memory mapping to reduce peak memory usage and stay within limit.
guard let profile = try? ALTProvisioningProfile(url: fileURL, options: [.mappedIfSafe]) else { continue }
2023-03-01 00:48:36 -05:00
if installingBundleIDs.contains(profile.bundleIdentifier) || (activeProfiles?.contains(profile.bundleIdentifier) == false && profile.isFreeProvisioningProfile) {
try FileManager.default.removeItem(at: fileURL)
2023-03-01 00:48:36 -05:00
} else {
2023-03-02 00:40:11 -05:00
os_log("Ignoring: %@ %@", type: .info , profile.bundleIdentifier, profile.uuid)
}
}
2023-03-01 00:48:36 -05:00
for profile in profiles {
let destinationURL = URL.profilesDirectoryURL.appendingPathComponent(profile.uuid.uuidString.lowercased())
try profile.data.write(to: destinationURL, options: .atomic)
}
2023-03-01 00:48:36 -05:00
completionHandler(.success(()))
2023-03-01 00:48:36 -05:00
} catch {
completionHandler(.failure(error))
}
2023-03-01 00:48:36 -05:00
// Notify system to prevent accidentally untrusting developer certificate.
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), .updatedProvisioningProfiles, nil, nil, true)
}
}
2023-03-01 00:48:36 -05:00
func removeProvisioningProfiles(forBundleIdentifiers bundleIdentifiers: Set<String>, completionHandler: @escaping (Result<Void, Error>) -> Void) {
let intent = NSFileAccessIntent.writingIntent(with: .profilesDirectoryURL, options: [])
2023-03-01 00:48:36 -05:00
fileCoordinator.coordinate(with: [intent], queue: profilesQueue) { error in
do {
let profileURLs = try FileManager.default.contentsOfDirectory(at: intent.url, includingPropertiesForKeys: nil, options: [])
2023-03-01 00:48:36 -05:00
for fileURL in profileURLs {
guard let profile = ALTProvisioningProfile(url: fileURL) else { continue }
2023-03-01 00:48:36 -05:00
if bundleIdentifiers.contains(profile.bundleIdentifier) {
try FileManager.default.removeItem(at: fileURL)
}
}
2023-03-01 00:48:36 -05:00
completionHandler(.success(()))
2023-03-01 00:48:36 -05:00
} catch {
completionHandler(.failure(error))
}
2023-03-01 00:48:36 -05:00
// Notify system to prevent accidentally untrusting developer certificate.
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), .updatedProvisioningProfiles, nil, nil, true)
}
}
}