mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-09 06:43:25 +01:00
[AltServer] Fixes “Max Apps Allowed” error when updating an already-installed app
Removes provisioning profile from device before installation, then adds them back afterwards
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
#include <libimobiledevice/installation_proxy.h>
|
#include <libimobiledevice/installation_proxy.h>
|
||||||
#include <libimobiledevice/notification_proxy.h>
|
#include <libimobiledevice/notification_proxy.h>
|
||||||
#include <libimobiledevice/afc.h>
|
#include <libimobiledevice/afc.h>
|
||||||
|
#include <libimobiledevice/misagent.h>
|
||||||
|
|
||||||
void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *udid);
|
void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *udid);
|
||||||
|
|
||||||
@@ -64,18 +65,52 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError";
|
|||||||
strncpy(uuidString, (const char *)UUID.UUIDString.UTF8String, UUID.UUIDString.length);
|
strncpy(uuidString, (const char *)UUID.UUIDString.UTF8String, UUID.UUIDString.length);
|
||||||
uuidString[UUID.UUIDString.length] = '\0';
|
uuidString[UUID.UUIDString.length] = '\0';
|
||||||
|
|
||||||
idevice_t device = NULL;
|
__block idevice_t device = NULL;
|
||||||
lockdownd_client_t client = NULL;
|
__block lockdownd_client_t client = NULL;
|
||||||
instproxy_client_t ipc = NULL;
|
__block instproxy_client_t ipc = NULL;
|
||||||
np_client_t np = NULL;
|
__block afc_client_t afc = NULL;
|
||||||
afc_client_t afc = NULL;
|
__block misagent_client_t mis = NULL;
|
||||||
lockdownd_service_descriptor_t service = NULL;
|
__block lockdownd_service_descriptor_t service = NULL;
|
||||||
|
|
||||||
|
NSURL *removedProfilesDirectoryURL = [[[NSFileManager defaultManager] temporaryDirectory] URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
|
||||||
|
|
||||||
void (^finish)(NSError *error) = ^(NSError *error) {
|
void (^finish)(NSError *error) = ^(NSError *error) {
|
||||||
|
|
||||||
|
if ([[NSFileManager defaultManager] fileExistsAtPath:removedProfilesDirectoryURL.path isDirectory:nil])
|
||||||
|
{
|
||||||
|
// Reinstall all provisioning profiles we removed before installation.
|
||||||
|
|
||||||
|
NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:removedProfilesDirectoryURL.path error:nil];
|
||||||
|
for (NSString *filename in contents)
|
||||||
|
{
|
||||||
|
NSURL *fileURL = [removedProfilesDirectoryURL URLByAppendingPathComponent:filename];
|
||||||
|
|
||||||
|
ALTProvisioningProfile *provisioningProfile = [[ALTProvisioningProfile alloc] initWithURL:fileURL];
|
||||||
|
if (provisioningProfile == nil)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
plist_t pdata = plist_new_data((const char *)provisioningProfile.data.bytes, provisioningProfile.data.length);
|
||||||
|
|
||||||
|
if (misagent_install(mis, pdata) == MISAGENT_E_SUCCESS)
|
||||||
|
{
|
||||||
|
NSLog(@"Reinstalled profile: %@", provisioningProfile.identifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int code = misagent_get_status_code(mis);
|
||||||
|
NSLog(@"Failed to reinstall provisioning profile %@. (%@)", provisioningProfile.identifier, @(code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[NSFileManager defaultManager] removeItemAtURL:removedProfilesDirectoryURL error:nil];
|
||||||
|
}
|
||||||
|
|
||||||
instproxy_client_free(ipc);
|
instproxy_client_free(ipc);
|
||||||
afc_client_free(afc);
|
afc_client_free(afc);
|
||||||
lockdownd_client_free(client);
|
lockdownd_client_free(client);
|
||||||
|
misagent_client_free(mis);
|
||||||
idevice_free(device);
|
idevice_free(device);
|
||||||
lockdownd_service_descriptor_free(service);
|
lockdownd_service_descriptor_free(service);
|
||||||
|
|
||||||
@@ -206,7 +241,83 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError";
|
|||||||
|
|
||||||
NSLog(@"Finished writing to device.");
|
NSLog(@"Finished writing to device.");
|
||||||
|
|
||||||
NSProgress *installationProgress = [NSProgress progressWithTotalUnitCount:100 parent:progress pendingUnitCount:1];
|
/* Provisioning Profiles */
|
||||||
|
NSURL *provisioningProfileURL = [appBundleURL URLByAppendingPathComponent:@"embedded.mobileprovision"];
|
||||||
|
ALTProvisioningProfile *installationProvisioningProfile = [[ALTProvisioningProfile alloc] initWithURL:provisioningProfileURL];
|
||||||
|
if (installationProvisioningProfile != nil)
|
||||||
|
{
|
||||||
|
NSError *error = nil;
|
||||||
|
if (![[NSFileManager defaultManager] createDirectoryAtURL:removedProfilesDirectoryURL withIntermediateDirectories:YES attributes:nil error:&error])
|
||||||
|
{
|
||||||
|
return finish(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((lockdownd_start_service(client, "com.apple.misagent", &service) != LOCKDOWN_E_SUCCESS) || service == NULL)
|
||||||
|
{
|
||||||
|
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (misagent_client_new(device, service, &mis) != MISAGENT_E_SUCCESS)
|
||||||
|
{
|
||||||
|
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
|
||||||
|
}
|
||||||
|
|
||||||
|
plist_t profiles = NULL;
|
||||||
|
if (misagent_copy_all(mis, &profiles) != MISAGENT_E_SUCCESS)
|
||||||
|
{
|
||||||
|
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t profileCount = plist_array_get_size(profiles);
|
||||||
|
for (int i = 0; i < profileCount; i++)
|
||||||
|
{
|
||||||
|
plist_t profile = plist_array_get_item(profiles, i);
|
||||||
|
if (plist_get_node_type(profile) != PLIST_DATA)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *bytes = NULL;
|
||||||
|
uint64_t length = 0;
|
||||||
|
|
||||||
|
plist_get_data_val(profile, &bytes, &length);
|
||||||
|
if (bytes == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSData *data = [NSData dataWithBytes:(const void *)bytes length:length];
|
||||||
|
ALTProvisioningProfile *provisioningProfile = [[ALTProvisioningProfile alloc] initWithData:data];
|
||||||
|
|
||||||
|
if (![provisioningProfile.teamIdentifier isEqualToString:installationProvisioningProfile.teamIdentifier])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *filename = [NSString stringWithFormat:@"%@.mobileprovision", [[NSUUID UUID] UUIDString]];
|
||||||
|
NSURL *fileURL = [removedProfilesDirectoryURL URLByAppendingPathComponent:filename];
|
||||||
|
|
||||||
|
NSError *copyError = nil;
|
||||||
|
if (![provisioningProfile.data writeToURL:fileURL options:NSDataWritingAtomic error:©Error])
|
||||||
|
{
|
||||||
|
NSLog(@"Failed to copy profile to temporary URL. %@", copyError);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (misagent_remove(mis, provisioningProfile.identifier.UTF8String) == MISAGENT_E_SUCCESS)
|
||||||
|
{
|
||||||
|
NSLog(@"Removed provisioning profile: %@", provisioningProfile.identifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int code = misagent_get_status_code(mis);
|
||||||
|
NSLog(@"Failed to remove provisioning profile %@. Error Code: %@", provisioningProfile.identifier, @(code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lockdownd_client_free(client);
|
||||||
|
client = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
NSProgress *installationProgress = [NSProgress progressWithTotalUnitCount:100 parent:progress pendingUnitCount:1];
|
NSProgress *installationProgress = [NSProgress progressWithTotalUnitCount:100 parent:progress pendingUnitCount:1];
|
||||||
|
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ private extension ViewController
|
|||||||
{
|
{
|
||||||
let certificates = try Result(certificates, error).get()
|
let certificates = try Result(certificates, error).get()
|
||||||
|
|
||||||
guard let certificate = certificates.first(where: { $0.identifier == certificate.identifier }) else {
|
guard let certificate = certificates.first(where: { $0.serialNumber == certificate.serialNumber }) else {
|
||||||
throw InstallError.missingCertificate
|
throw InstallError.missingCertificate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class Keychain
|
|||||||
self.appleIDEmailAddress = nil
|
self.appleIDEmailAddress = nil
|
||||||
self.appleIDPassword = nil
|
self.appleIDPassword = nil
|
||||||
self.signingCertificatePrivateKey = nil
|
self.signingCertificatePrivateKey = nil
|
||||||
self.signingCertificateIdentifier = nil
|
self.signingCertificateSerialNumber = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,13 +62,13 @@ extension Keychain
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var signingCertificateIdentifier: String? {
|
var signingCertificateSerialNumber: String? {
|
||||||
get {
|
get {
|
||||||
let identifier = try? self.keychain.get("signingCertificateIdentifier")
|
let serialNumber = try? self.keychain.get("signingCertificateSerialNumber")
|
||||||
return identifier
|
return serialNumber
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
self.keychain["signingCertificateIdentifier"] = newValue
|
self.keychain["signingCertificateSerialNumber"] = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class AuthenticationOperation: ResultOperation<ALTSigner>
|
|||||||
Keychain.shared.appleIDEmailAddress = altAccount.appleID // "account" may have nil appleID since we just saved.
|
Keychain.shared.appleIDEmailAddress = altAccount.appleID // "account" may have nil appleID since we just saved.
|
||||||
Keychain.shared.appleIDPassword = self.appleIDPassword
|
Keychain.shared.appleIDPassword = self.appleIDPassword
|
||||||
|
|
||||||
Keychain.shared.signingCertificateIdentifier = signer.certificate.identifier
|
Keychain.shared.signingCertificateSerialNumber = signer.certificate.serialNumber
|
||||||
Keychain.shared.signingCertificatePrivateKey = signer.certificate.privateKey
|
Keychain.shared.signingCertificatePrivateKey = signer.certificate.privateKey
|
||||||
|
|
||||||
super.finish(.success(signer))
|
super.finish(.success(signer))
|
||||||
@@ -299,7 +299,7 @@ private extension AuthenticationOperation
|
|||||||
{
|
{
|
||||||
let certificates = try Result(certificates, error).get()
|
let certificates = try Result(certificates, error).get()
|
||||||
|
|
||||||
guard let certificate = certificates.first(where: { $0.identifier == certificate.identifier }) else {
|
guard let certificate = certificates.first(where: { $0.serialNumber == certificate.serialNumber }) else {
|
||||||
throw AuthenticationError.missingCertificate
|
throw AuthenticationError.missingCertificate
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,9 +349,9 @@ private extension AuthenticationOperation
|
|||||||
let certificates = try Result(certificates, error).get()
|
let certificates = try Result(certificates, error).get()
|
||||||
|
|
||||||
if
|
if
|
||||||
let identifier = Keychain.shared.signingCertificateIdentifier,
|
let serialNumber = Keychain.shared.signingCertificateSerialNumber,
|
||||||
let privateKey = Keychain.shared.signingCertificatePrivateKey,
|
let privateKey = Keychain.shared.signingCertificatePrivateKey,
|
||||||
let certificate = certificates.first(where: { $0.identifier == identifier })
|
let certificate = certificates.first(where: { $0.serialNumber == serialNumber })
|
||||||
{
|
{
|
||||||
certificate.privateKey = privateKey
|
certificate.privateKey = privateKey
|
||||||
completionHandler(.success(certificate))
|
completionHandler(.success(certificate))
|
||||||
|
|||||||
2
Dependencies/AltSign
vendored
2
Dependencies/AltSign
vendored
Submodule Dependencies/AltSign updated: c99aa73a89...ae919bedd2
Reference in New Issue
Block a user