Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions AltStore/Operations/FetchAnisetteDataOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ private extension URL
static let appleGSALookup = URL(string: "https://gsa.apple.com/grandslam/GsService2/lookup")!
}

// Anisette servers generate data with Android's CoreADI, and Apple now rejects it (-80045)
// unless the client info also claims to be Android.
// Based on xtool: https://github.com/xtool-org/xtool/pull/337
private let androidClientInfo = "<Pixel 7> <Android;14;UQ1A.240205.002> <com.apple.AuthKit/1 (com.apple.akd/1.0)>"

extension FetchAnisetteDataOperation
{
fileprivate struct AnisetteIdentity
Expand Down Expand Up @@ -249,17 +254,18 @@ private extension FetchAnisetteDataOperation
Keychain.shared.anisetteIdentityKey = identity.bytes
}

// 3. Provision against this server if we don't have a cached adi.pb
// 3. Provision against this server if we don't have a cached adi.pb (provisioned with the current client info)
let adiPB: Data
if let pb = Keychain.shared.anisetteADIPB
if let pb = Keychain.shared.anisetteADIPB, Keychain.shared.anisetteADIPBClientInfo == androidClientInfo
{
adiPB = pb
}
else
{
Logger.sideload.notice("No cached adi.pb; running anisette provisioning against \(serverURL.absoluteString, privacy: .public).")
adiPB = try await self.provision(against: serverURL, clientInfo: response.clientInfo, userAgent: response.userAgent, identity: identity)
Logger.sideload.notice("No up-to-date cached adi.pb; running anisette provisioning against \(serverURL.absoluteString, privacy: .public).")
adiPB = try await self.provision(against: serverURL, clientInfo: androidClientInfo, userAgent: response.userAgent, identity: identity)
Keychain.shared.anisetteADIPB = adiPB
Keychain.shared.anisetteADIPBClientInfo = androidClientInfo
}

// 4. Fetch anisette headers
Expand All @@ -273,7 +279,7 @@ private extension FetchAnisetteDataOperation
routingInfo: routingInfo,
deviceUniqueIdentifier: identity.deviceID,
deviceSerialNumber: "C02LKHBBFD57",
deviceDescription: response.clientInfo,
deviceDescription: androidClientInfo,
date: .now,
locale: .current,
timeZone: .current
Expand Down
4 changes: 4 additions & 0 deletions AltStoreCore/Components/Keychain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ public class Keychain
@KeychainItem(key: "anisetteADIPB", synchronizable: false)
public var anisetteADIPB: Data?

// Client info anisetteADIPB was provisioned with.
@KeychainItem(key: "anisetteADIPBClientInfo", synchronizable: false)
public var anisetteADIPBClientInfo: String?

@KeychainItem(key: "devicePairingFile", synchronizable: false)
public var devicePairingFile: Data?

Expand Down