mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-09 06:43:25 +01:00
Refreshes apps by installing provisioning profiles when possible
Assuming the certificate used to originally sign an app is still valid, we can refresh an app simply by installing new provisioning profiles. However, if the signing certificate is no longer valid, we fall back to the old method of resigning + reinstalling.
This commit is contained in:
@@ -32,9 +32,9 @@ enum AuthenticationError: LocalizedError
|
||||
}
|
||||
|
||||
@objc(AuthenticationOperation)
|
||||
class AuthenticationOperation: ResultOperation<(ALTSigner, ALTAppleAPISession)>
|
||||
class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, ALTAppleAPISession)>
|
||||
{
|
||||
let group: OperationGroup
|
||||
let context: AuthenticatedOperationContext
|
||||
|
||||
private weak var presentingViewController: UIViewController?
|
||||
|
||||
@@ -56,22 +56,23 @@ class AuthenticationOperation: ResultOperation<(ALTSigner, ALTAppleAPISession)>
|
||||
|
||||
private var submitCodeAction: UIAlertAction?
|
||||
|
||||
init(group: OperationGroup, presentingViewController: UIViewController?)
|
||||
init(context: AuthenticatedOperationContext, presentingViewController: UIViewController?)
|
||||
{
|
||||
self.group = group
|
||||
self.context = context
|
||||
self.presentingViewController = presentingViewController
|
||||
|
||||
super.init()
|
||||
|
||||
|
||||
self.context.authenticationOperation = self
|
||||
self.operationQueue.name = "com.altstore.AuthenticationOperation"
|
||||
self.progress.totalUnitCount = 3
|
||||
self.progress.totalUnitCount = 4
|
||||
}
|
||||
|
||||
override func main()
|
||||
{
|
||||
super.main()
|
||||
|
||||
if let error = self.group.error
|
||||
if let error = self.context.error
|
||||
{
|
||||
self.finish(.failure(error))
|
||||
return
|
||||
@@ -85,6 +86,7 @@ class AuthenticationOperation: ResultOperation<(ALTSigner, ALTAppleAPISession)>
|
||||
{
|
||||
case .failure(let error): self.finish(.failure(error))
|
||||
case .success(let account, let session):
|
||||
self.context.session = session
|
||||
self.progress.completedUnitCount += 1
|
||||
|
||||
// Fetch Team
|
||||
@@ -95,6 +97,7 @@ class AuthenticationOperation: ResultOperation<(ALTSigner, ALTAppleAPISession)>
|
||||
{
|
||||
case .failure(let error): self.finish(.failure(error))
|
||||
case .success(let team):
|
||||
self.context.team = team
|
||||
self.progress.completedUnitCount += 1
|
||||
|
||||
// Fetch Certificate
|
||||
@@ -105,22 +108,33 @@ class AuthenticationOperation: ResultOperation<(ALTSigner, ALTAppleAPISession)>
|
||||
{
|
||||
case .failure(let error): self.finish(.failure(error))
|
||||
case .success(let certificate):
|
||||
self.context.certificate = certificate
|
||||
self.progress.completedUnitCount += 1
|
||||
|
||||
// Save account/team to disk.
|
||||
self.save(team) { (result) in
|
||||
// Register Device
|
||||
self.registerCurrentDevice(for: team, session: session) { (result) in
|
||||
guard !self.isCancelled else { return self.finish(.failure(OperationError.cancelled)) }
|
||||
|
||||
switch result
|
||||
{
|
||||
case .failure(let error): self.finish(.failure(error))
|
||||
case .success:
|
||||
let signer = ALTSigner(team: team, certificate: certificate)
|
||||
self.progress.completedUnitCount += 1
|
||||
|
||||
// Must cache App IDs _after_ saving account/team to disk.
|
||||
self.cacheAppIDs(signer: signer, session: session) { (result) in
|
||||
let result = result.map { _ in (signer, session) }
|
||||
self.finish(result)
|
||||
// Save account/team to disk.
|
||||
self.save(team) { (result) in
|
||||
guard !self.isCancelled else { return self.finish(.failure(OperationError.cancelled)) }
|
||||
|
||||
switch result
|
||||
{
|
||||
case .failure(let error): self.finish(.failure(error))
|
||||
case .success:
|
||||
// Must cache App IDs _after_ saving account/team to disk.
|
||||
self.cacheAppIDs(team: team, session: session) { (result) in
|
||||
let result = result.map { _ in (team, certificate, session) }
|
||||
self.finish(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,21 +187,21 @@ class AuthenticationOperation: ResultOperation<(ALTSigner, ALTAppleAPISession)>
|
||||
}
|
||||
}
|
||||
|
||||
override func finish(_ result: Result<(ALTSigner, ALTAppleAPISession), Error>)
|
||||
override func finish(_ result: Result<(ALTTeam, ALTCertificate, ALTAppleAPISession), Error>)
|
||||
{
|
||||
guard !self.isFinished else { return }
|
||||
|
||||
print("Finished authenticating with result:", result)
|
||||
print("Finished authenticating with result:", result.error?.localizedDescription ?? "success")
|
||||
|
||||
let context = DatabaseManager.shared.persistentContainer.newBackgroundContext()
|
||||
context.perform {
|
||||
do
|
||||
{
|
||||
let (signer, session) = try result.get()
|
||||
let (altTeam, altCertificate, session) = try result.get()
|
||||
|
||||
guard
|
||||
let account = Account.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Account.identifier), signer.team.account.identifier), in: context),
|
||||
let team = Team.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Team.identifier), signer.team.identifier), in: context)
|
||||
let account = Account.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Account.identifier), altTeam.account.identifier), in: context),
|
||||
let team = Team.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Team.identifier), altTeam.identifier), in: context)
|
||||
else { throw AuthenticationError.noTeam }
|
||||
|
||||
// Account
|
||||
@@ -214,24 +228,19 @@ class AuthenticationOperation: ResultOperation<(ALTSigner, ALTAppleAPISession)>
|
||||
team.isActiveTeam = false
|
||||
}
|
||||
|
||||
if let altStoreApp = InstalledApp.fetchAltStore(in: context), altStoreApp.team == nil
|
||||
{
|
||||
// No team assigned to AltStore app yet, so assume this team was used to originally install it.
|
||||
altStoreApp.team = team
|
||||
}
|
||||
|
||||
// Save
|
||||
try context.save()
|
||||
|
||||
// Update keychain
|
||||
Keychain.shared.appleIDEmailAddress = signer.team.account.appleID
|
||||
Keychain.shared.appleIDEmailAddress = altTeam.account.appleID
|
||||
Keychain.shared.appleIDPassword = self.appleIDPassword
|
||||
|
||||
Keychain.shared.signingCertificate = signer.certificate.p12Data()
|
||||
Keychain.shared.signingCertificatePassword = signer.certificate.machineIdentifier
|
||||
Keychain.shared.signingCertificate = altCertificate.p12Data()
|
||||
Keychain.shared.signingCertificatePassword = altCertificate.machineIdentifier
|
||||
|
||||
self.showInstructionsIfNecessary() { (didShowInstructions) in
|
||||
|
||||
let signer = ALTSigner(team: altTeam, certificate: altCertificate)
|
||||
// Refresh screen must go last since a successful refresh will cause the app to quit.
|
||||
self.showRefreshScreenIfNecessary(signer: signer, session: session) { (didShowRefreshAlert) in
|
||||
super.finish(result)
|
||||
@@ -340,7 +349,7 @@ private extension AuthenticationOperation
|
||||
|
||||
func authenticate(appleID: String, password: String, completionHandler: @escaping (Result<(ALTAccount, ALTAppleAPISession), Swift.Error>) -> Void)
|
||||
{
|
||||
let fetchAnisetteDataOperation = FetchAnisetteDataOperation(group: self.group)
|
||||
let fetchAnisetteDataOperation = FetchAnisetteDataOperation(context: self.context)
|
||||
fetchAnisetteDataOperation.resultHandler = { (result) in
|
||||
switch result
|
||||
{
|
||||
@@ -557,13 +566,38 @@ private extension AuthenticationOperation
|
||||
}
|
||||
}
|
||||
|
||||
func cacheAppIDs(signer: ALTSigner, session: ALTAppleAPISession, completionHandler: @escaping (Result<Void, Error>) -> Void)
|
||||
func registerCurrentDevice(for team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTDevice, Error>) -> Void)
|
||||
{
|
||||
let group = OperationGroup()
|
||||
group.signer = signer
|
||||
group.session = session
|
||||
guard let udid = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.deviceID) as? String else {
|
||||
return completionHandler(.failure(OperationError.unknownUDID))
|
||||
}
|
||||
|
||||
let fetchAppIDsOperation = FetchAppIDsOperation(group: group)
|
||||
ALTAppleAPI.shared.fetchDevices(for: team, session: session) { (devices, error) in
|
||||
do
|
||||
{
|
||||
let devices = try Result(devices, error).get()
|
||||
|
||||
if let device = devices.first(where: { $0.identifier == udid })
|
||||
{
|
||||
completionHandler(.success(device))
|
||||
}
|
||||
else
|
||||
{
|
||||
ALTAppleAPI.shared.registerDevice(name: UIDevice.current.name, identifier: udid, team: team, session: session) { (device, error) in
|
||||
completionHandler(Result(device, error))
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
completionHandler(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cacheAppIDs(team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<Void, Error>) -> Void)
|
||||
{
|
||||
let fetchAppIDsOperation = FetchAppIDsOperation(context: self.context)
|
||||
fetchAppIDsOperation.resultHandler = { (result) in
|
||||
do
|
||||
{
|
||||
@@ -611,8 +645,7 @@ private extension AuthenticationOperation
|
||||
#else
|
||||
DispatchQueue.main.async {
|
||||
let refreshViewController = self.storyboard.instantiateViewController(withIdentifier: "refreshAltStoreViewController") as! RefreshAltStoreViewController
|
||||
refreshViewController.signer = signer
|
||||
refreshViewController.session = session
|
||||
refreshViewController.context = self.context
|
||||
refreshViewController.completionHandler = { _ in
|
||||
completionHandler(true)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user