Skip to content
Draft
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
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ let package = Package(
"DeveloperAPI",
"CXKit",
"XUtils",
.product(name: "XADI", package: "xadi", condition: .when(platforms: [.linux])),
.product(name: "XADI", package: "xadi", condition: .when(platforms: [.linux, .macOS])),
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
.product(name: "Dependencies", package: "swift-dependencies"),
.product(name: "SwiftyMobileDevice", package: "SwiftyMobileDevice"),
Expand Down
27 changes: 26 additions & 1 deletion Sources/XKit/GrandSlam/Anisette/ADIDataProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ public struct ADIDataProvider: AnisetteDataProvider {
try? storage.setString(nil, forKey: Self.routingInfoKey)
}

public var providerVersion: String? {
#if os(macOS)
return "1"
#else
return nil
#endif
}

public func provisioningData() -> ProvisioningData? {
guard let provisioningInfo = try? storage.data(forKey: Self.provisioningKey),
let routingInfoString = try? storage.string(forKey: Self.routingInfoKey),
Expand Down Expand Up @@ -280,6 +288,23 @@ public struct ADIDataProvider: AnisetteDataProvider {

}

public struct ADIError: Error {
public struct ADIError: Error, CustomStringConvertible {
public var code: Int

public var description: String {
switch code {
case -45061:
return """
You were logged out. Please log in again with `xtool auth`.

If you see this repeatedly, please file an issue at https://github.com/xtool-org/xtool/issues/new/choose
"""
default:
return """
Apple Anisette library returned error \(code). Please try logging in again with `xtool auth`.

If this problem persists, file an issue at https://github.com/xtool-org/xtool/issues/new/choose
"""
}
}
}
11 changes: 9 additions & 2 deletions Sources/XKit/GrandSlam/Anisette/AnisetteDataProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ import Foundation
import Dependencies

public protocol AnisetteDataProvider: Sendable {
/// Stored alongside login data. If the provider reports a new version, we log out and reset provisioning.
///
/// The default implementation returns `nil`.
var providerVersion: String? { get }

// This is a suggestion and not a requirement.
func resetProvisioning() async
func resetProvisioning()

func provisioningData() -> ProvisioningData?

func fetchAnisetteData() async throws -> AnisetteData
Expand All @@ -24,8 +30,9 @@ public struct ProvisioningData: Hashable, Codable, Sendable {
}

extension AnisetteDataProvider {
public var providerVersion: String? { nil }
public func provisioningData() -> ProvisioningData? { nil }
public func resetProvisioning() async {}
public func resetProvisioning() {}
}

extension DependencyValues {
Expand Down
2 changes: 1 addition & 1 deletion Sources/XToolSupport/AuthCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ struct AuthLogoutCommand: AsyncParsableCommand {

if reset2FA {
@Dependency(\.anisetteDataProvider) var anisetteProvider
await anisetteProvider.resetProvisioning()
anisetteProvider.resetProvisioning()
print("Forgot device")
}
}
Expand Down
25 changes: 24 additions & 1 deletion Sources/XToolSupport/AuthToken.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ enum AuthToken: Codable, CustomStringConvertible {
var token: String
var expiry: Date
var teamID: String
var anisetteVersion: String?

init(appleID: String, adsid: String, token: String, expiry: Date, teamID: String) {
self.appleID = appleID
self.adsid = adsid
self.token = token
self.expiry = expiry
self.teamID = teamID
@Dependency(\.anisetteDataProvider) var anisetteProvider
self.anisetteVersion = anisetteProvider.providerVersion
}
}

struct AppStoreConnect: Codable {
Expand Down Expand Up @@ -58,7 +69,19 @@ extension AuthToken {
guard let data = try storage.data(forKey: "XTLAuthToken") else {
return nil
}
return try decoder.decode(AuthToken.self, from: data)
let decoded = try decoder.decode(AuthToken.self, from: data)
switch decoded {
case .xcode(let xcode):
@Dependency(\.anisetteDataProvider) var anisetteProvider
guard xcode.anisetteVersion == anisetteProvider.providerVersion else {
try? clear()
anisetteProvider.resetProvisioning()
return nil
}
case .appStoreConnect:
break
}
return decoded
}

static func clear() throws {
Expand Down
2 changes: 2 additions & 0 deletions macOS/Support/XToolMac.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)sh.xtool.keychain</string>
Expand Down
Loading