[AltServer] Manages active/inactive profiles when installing apps

This commit is contained in:
Riley Testut
2020-03-11 13:51:39 -07:00
parent 5e25593c3d
commit 06fed802b1
5 changed files with 76 additions and 57 deletions

View File

@@ -262,11 +262,15 @@ public struct PrepareAppRequest: ServerMessageProtocol
public struct BeginInstallationRequest: ServerMessageProtocol public struct BeginInstallationRequest: ServerMessageProtocol
{ {
public var version = 1 public var version = 2
public var identifier = "BeginInstallationRequest" public var identifier = "BeginInstallationRequest"
public init() // If activeProfiles is non-nil, then AltServer should remove all profiles except active ones.
public var activeProfiles: Set<String>?
public init(activeProfiles: Set<String>?)
{ {
self.activeProfiles = activeProfiles
} }
} }

View File

@@ -351,10 +351,10 @@ private extension ConnectionManager
switch result switch result
{ {
case .failure(let error): finish(.failure(error)) case .failure(let error): finish(.failure(error))
case .success(.beginInstallation): case .success(.beginInstallation(let installRequest)):
print("Installing to device \(request.udid)...") print("Installing to device \(request.udid)...")
self.installApp(at: fileURL, toDeviceWithUDID: request.udid, connection: connection) { (result) in self.installApp(at: fileURL, toDeviceWithUDID: request.udid, activeProvisioningProfiles: installRequest.activeProfiles, connection: connection) { (result) in
print("Installed to device with result:", result) print("Installed to device with result:", result)
switch result switch result
{ {
@@ -403,14 +403,14 @@ private extension ConnectionManager
} }
} }
func installApp(at fileURL: URL, toDeviceWithUDID udid: String, connection: ClientConnection, completionHandler: @escaping (Result<Void, ALTServerError>) -> Void) func installApp(at fileURL: URL, toDeviceWithUDID udid: String, activeProvisioningProfiles: Set<String>?, connection: ClientConnection, completionHandler: @escaping (Result<Void, ALTServerError>) -> Void)
{ {
let serialQueue = DispatchQueue(label: "com.altstore.ConnectionManager.installQueue", qos: .default) let serialQueue = DispatchQueue(label: "com.altstore.ConnectionManager.installQueue", qos: .default)
var isSending = false var isSending = false
var observation: NSKeyValueObservation? var observation: NSKeyValueObservation?
let progress = ALTDeviceManager.shared.installApp(at: fileURL, toDeviceWithUDID: udid) { (success, error) in let progress = ALTDeviceManager.shared.installApp(at: fileURL, toDeviceWithUDID: udid, activeProvisioningProfiles: activeProvisioningProfiles) { (success, error) in
print("Installed app with result:", error == nil ? "Success" : error!.localizedDescription) print("Installed app with result:", error == nil ? "Success" : error!.localizedDescription)
if let error = error.map({ $0 as? ALTServerError ?? ALTServerError(.unknown) }) if let error = error.map({ $0 as? ALTServerError ?? ALTServerError(.unknown) })

View File

@@ -536,7 +536,8 @@ To prevent this from happening, feel free to try again with another Apple ID to
{ {
try Result(success, error).get() try Result(success, error).get()
ALTDeviceManager.shared.installApp(at: application.fileURL, toDeviceWithUDID: device.identifier) { (success, error) in let activeProfiles: Set<String>? = (team.type == .free) ? [profile.bundleIdentifier] : nil
ALTDeviceManager.shared.installApp(at: application.fileURL, toDeviceWithUDID: device.identifier, activeProvisioningProfiles: activeProfiles) { (success, error) in
completionHandler(Result(success, error)) completionHandler(Result(success, error))
} }
} }

View File

@@ -27,7 +27,7 @@ extern NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification
- (void)start; - (void)start;
/* App Installation */ /* App Installation */
- (NSProgress *)installAppAtURL:(NSURL *)fileURL toDeviceWithUDID:(NSString *)udid completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler; - (NSProgress *)installAppAtURL:(NSURL *)fileURL toDeviceWithUDID:(NSString *)udid activeProvisioningProfiles:(nullable NSSet<NSString *> *)activeProvisioningProfiles completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler;
- (void)installProvisioningProfiles:(NSSet<ALTProvisioningProfile *> *)provisioningProfiles toDeviceWithUDID:(NSString *)udid activeProvisioningProfiles:(nullable NSSet<NSString *> *)activeProvisioningProfiles removeInactiveProvisioningProfiles:(BOOL)removeInactiveProvisioningProfiles completionHandler:(void (^)(NSDictionary<ALTProvisioningProfile *, NSError *> *errors))completionHandler; - (void)installProvisioningProfiles:(NSSet<ALTProvisioningProfile *> *)provisioningProfiles toDeviceWithUDID:(NSString *)udid activeProvisioningProfiles:(nullable NSSet<NSString *> *)activeProvisioningProfiles removeInactiveProvisioningProfiles:(BOOL)removeInactiveProvisioningProfiles completionHandler:(void (^)(NSDictionary<ALTProvisioningProfile *, NSError *> *errors))completionHandler;
- (void)removeProvisioningProfilesForBundleIdentifiers:(NSSet<NSString *> *)bundleIdentifiers fromDeviceWithUDID:(NSString *)udid completionHandler:(void (^)(NSDictionary<NSString *, NSError *> *errors))completionHandler; - (void)removeProvisioningProfilesForBundleIdentifiers:(NSSet<NSString *> *)bundleIdentifiers fromDeviceWithUDID:(NSString *)udid completionHandler:(void (^)(NSDictionary<NSString *, NSError *> *errors))completionHandler;

View File

@@ -71,7 +71,7 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
#pragma mark - App Installation - #pragma mark - App Installation -
- (NSProgress *)installAppAtURL:(NSURL *)fileURL toDeviceWithUDID:(NSString *)udid completionHandler:(void (^)(BOOL, NSError * _Nullable))completionHandler - (NSProgress *)installAppAtURL:(NSURL *)fileURL toDeviceWithUDID:(NSString *)udid activeProvisioningProfiles:(nullable NSSet<NSString *> *)activeProvisioningProfiles completionHandler:(void (^)(BOOL, NSError * _Nullable))completionHandler
{ {
NSProgress *progress = [NSProgress discreteProgressWithTotalUnitCount:4]; NSProgress *progress = [NSProgress discreteProgressWithTotalUnitCount:4];
@@ -88,41 +88,42 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
__block misagent_client_t mis = NULL; __block misagent_client_t mis = NULL;
__block lockdownd_service_descriptor_t service = NULL; __block lockdownd_service_descriptor_t service = NULL;
NSURL *removedProfilesDirectoryURL = [[[NSFileManager defaultManager] temporaryDirectory] URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; NSMutableDictionary<NSString *, ALTProvisioningProfile *> *cachedProfiles = [NSMutableDictionary dictionary];
NSMutableDictionary<NSString *, ALTProvisioningProfile *> *preferredProfiles = [NSMutableDictionary dictionary]; NSMutableSet<ALTProvisioningProfile *> *installedProfiles = [NSMutableSet set];
void (^finish)(NSError *error) = ^(NSError *error) { void (^finish)(NSError *error) = ^(NSError *e) {
__block NSError *error = e;
if ([[NSFileManager defaultManager] fileExistsAtPath:removedProfilesDirectoryURL.path isDirectory:nil]) if (activeProvisioningProfiles != nil)
{ {
// Reinstall all provisioning profiles we removed before installation. // Remove installed provisioning profiles if they're not active.
NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:removedProfilesDirectoryURL.path error:nil]; for (ALTProvisioningProfile *installedProfile in installedProfiles)
for (NSString *filename in contents)
{ {
NSURL *fileURL = [removedProfilesDirectoryURL URLByAppendingPathComponent:filename]; if (![activeProvisioningProfiles containsObject:installedProfile.bundleIdentifier])
ALTProvisioningProfile *provisioningProfile = [[ALTProvisioningProfile alloc] initWithURL:fileURL];
if (provisioningProfile == nil)
{ {
continue; NSError *removeError = nil;
if (![self removeProvisioningProfile:installedProfile misagent:mis error:&removeError])
{
if (error == nil)
{
error = removeError;
}
}
} }
}
ALTProvisioningProfile *preferredProfile = preferredProfiles[provisioningProfile.bundleIdentifier]; }
if (![preferredProfile isEqual:provisioningProfile])
{ [cachedProfiles enumerateKeysAndObjectsUsingBlock:^(NSString *bundleID, ALTProvisioningProfile *profile, BOOL * _Nonnull stop) {
continue; NSError *installError = nil;
} if (![self installProvisioningProfile:profile misagent:mis error:&installError])
{
NSError *installError = nil; if (error == nil)
if (![self installProvisioningProfile:preferredProfile misagent:mis error:&installError])
{ {
error = installError; error = installError;
} }
} }
}];
[[NSFileManager defaultManager] removeItemAtURL:removedProfilesDirectoryURL error:nil];
}
instproxy_client_free(ipc); instproxy_client_free(ipc);
afc_client_free(afc); afc_client_free(afc);
@@ -278,17 +279,24 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
service = NULL; service = NULL;
} }
ALTApplication *application = [[ALTApplication alloc] initWithFileURL:appBundleURL];
if (application.provisioningProfile)
{
[installedProfiles addObject:application.provisioningProfile];
}
for (ALTApplication *appExtension in application.appExtensions)
{
if (appExtension.provisioningProfile)
{
[installedProfiles addObject:appExtension.provisioningProfile];
}
}
/* Provisioning Profiles */ /* Provisioning Profiles */
NSURL *provisioningProfileURL = [appBundleURL URLByAppendingPathComponent:@"embedded.mobileprovision"]; if (activeProvisioningProfiles != nil)
ALTProvisioningProfile *installationProvisioningProfile = [[ALTProvisioningProfile alloc] initWithURL:provisioningProfileURL];
if (installationProvisioningProfile != nil)
{ {
NSError *error = nil; NSError *error = nil;
if (![[NSFileManager defaultManager] createDirectoryAtURL:removedProfilesDirectoryURL withIntermediateDirectories:YES attributes:nil error:&error])
{
return finish(error);
}
NSArray<ALTProvisioningProfile *> *provisioningProfiles = [self copyProvisioningProfilesWithClient:mis error:&error]; NSArray<ALTProvisioningProfile *> *provisioningProfiles = [self copyProvisioningProfilesWithClient:mis error:&error];
if (provisioningProfiles == nil) if (provisioningProfiles == nil)
{ {
@@ -302,27 +310,33 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
continue; continue;
} }
ALTProvisioningProfile *preferredProfile = preferredProfiles[provisioningProfile.bundleIdentifier]; BOOL installingProfile = NO;
if (preferredProfile != nil) for (ALTProvisioningProfile *installedProfile in installedProfiles)
{ {
if ([provisioningProfile.expirationDate compare:preferredProfile.expirationDate] == NSOrderedDescending) if ([installedProfile.bundleIdentifier isEqualToString:provisioningProfile.bundleIdentifier])
{ {
preferredProfiles[provisioningProfile.bundleIdentifier] = provisioningProfile; installingProfile = YES;
break;
} }
} }
else
if ([activeProvisioningProfiles containsObject:provisioningProfile.bundleIdentifier] && !installingProfile)
{ {
preferredProfiles[provisioningProfile.bundleIdentifier] = provisioningProfile; // We're not installing this provisioning profile, but it is active,
} // so we'll cache it to install it again after installing this app.
NSString *filename = [NSString stringWithFormat:@"%@.mobileprovision", [[NSUUID UUID] UUIDString]]; ALTProvisioningProfile *preferredProfile = cachedProfiles[provisioningProfile.bundleIdentifier];
NSURL *fileURL = [removedProfilesDirectoryURL URLByAppendingPathComponent:filename]; if (preferredProfile != nil)
{
NSError *copyError = nil; if ([provisioningProfile.expirationDate compare:preferredProfile.expirationDate] == NSOrderedDescending)
if (![provisioningProfile.data writeToURL:fileURL options:NSDataWritingAtomic error:&copyError]) {
{ cachedProfiles[provisioningProfile.bundleIdentifier] = provisioningProfile;
NSLog(@"Failed to copy profile to temporary URL. %@", copyError); }
continue; }
else
{
cachedProfiles[provisioningProfile.bundleIdentifier] = provisioningProfile;
}
} }
if (![self removeProvisioningProfile:provisioningProfile misagent:mis error:&error]) if (![self removeProvisioningProfile:provisioningProfile misagent:mis error:&error])