Skip to content

Commit

Permalink
- Merge-Upstream: Rebased recent commits from rileytestut/AltSign - p…
Browse files Browse the repository at this point in the history
…ossibly removes need for 2FA code on iOS 18.1+ (#3)
  • Loading branch information
mahee96 authored Nov 30, 2024
1 parent cc6189f commit 74c9572
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 66 deletions.
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import PackageDescription
let package = Package(
name: "AltSign",
platforms: [
.iOS(.v12),
.macOS(.v10_14)
.iOS(.v14),
.macOS(.v11),
],
products: [
// MARK: - AltSign
Expand Down
75 changes: 47 additions & 28 deletions Sources/AltSign/ALTAppleAPI+Authentication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,21 @@ import Foundation
@_exported import CAltSign
import CAltSign.Private

public extension ALTAppleAPI {
public extension ALTAppleAPIError
{
static func unknown(userInfo: [String: Any] = [:], sourceFile: String = #fileID, sourceLine: UInt = #line) -> ALTAppleAPIError
{
var userInfo = userInfo
userInfo[ALTSourceFileErrorKey] = sourceFile
userInfo[ALTSourceLineErrorKey] = sourceLine

let error = ALTAppleAPIError(.unknown, userInfo: userInfo)
return error
}
}

public extension ALTAppleAPI
{
@objc func authenticate(appleID unsanitizedAppleID: String,
password: String,
anisetteData: ALTAnisetteData,
Expand Down Expand Up @@ -215,11 +229,12 @@ private extension ALTAppleAPI {

var request = self.makeTwoFactorCodeRequest(url: verifyURL, dsid: dsid, idmsToken: idmsToken, anisetteData: anisetteData)
request.allHTTPHeaderFields?["security-code"] = verificationCode

let verifyCodeTask = self.session.dataTask(with: request) { data, _, error in
do {
guard let data = data else { throw error ?? ALTAppleAPIError(.unknown) }


let verifyCodeTask = self.session.dataTask(with: request) { (data, response, error) in
do
{
guard let data = data else { throw error ?? ALTAppleAPIError.unknown() }

guard let responseDictionary = try PropertyListSerialization.propertyList(from: data, format: nil) as? [String: Any] else {
throw URLError(.badServerResponse)
}
Expand All @@ -230,10 +245,10 @@ private extension ALTAppleAPI {
switch errorCode {
case -21669: throw ALTAppleAPIError(.incorrectVerificationCode)
default:
guard let errorDescription = responseDictionary["em"] as? String else { throw ALTAppleAPIError(.unknown) }

guard let errorDescription = responseDictionary["em"] as? String else { throw ALTAppleAPIError.unknown() }
let localizedDescription = errorDescription + " (\(errorCode))"
throw ALTAppleAPIError(.unknown, userInfo: [NSLocalizedDescriptionKey: localizedDescription])
throw NSError(domain: ALTUnderlyingAppleAPIErrorDomain, code: errorCode, userInfo: [NSLocalizedDescriptionKey: localizedDescription])
}
} catch {
completionHandler(.failure(error))
Expand Down Expand Up @@ -331,20 +346,22 @@ private extension ALTAppleAPI {

requestCodeTask.resume()
}

func fetchAccount(session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTAccount, Error>) -> Void) {
let url = URL(string: "viewDeveloper.action", relativeTo: baseURL)!

sendRequest(with: url, additionalParameters: nil, session: session, team: nil) { responseDictionary, requestError in
do {
guard let responseDictionary = responseDictionary else { throw requestError ?? ALTAppleAPIError(.unknown) }


func fetchAccount(session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTAccount, Error>) -> Void)
{
let url = URL(string: "viewDeveloper.action", relativeTo: self.baseURL)!

self.sendRequest(with: url, additionalParameters: nil, session: session, team: nil) { (responseDictionary, requestError) in
do
{
guard let responseDictionary = responseDictionary else { throw requestError ?? ALTAppleAPIError.unknown() }

guard let account = try self.processResponse(responseDictionary, parseHandler: { () -> Any? in
guard let dictionary = responseDictionary["developer"] as? [String: Any] else { return nil }
let account = ALTAccount(responseDictionary: dictionary)
return account
}, resultCodeHandler: nil) as? ALTAccount else {
throw ALTAppleAPIError(.unknown)
throw ALTAppleAPIError.unknown()
}

completionHandler(.success(account))
Expand Down Expand Up @@ -378,27 +395,29 @@ private extension ALTAppleAPI {
request.httpMethod = "POST"
request.httpBody = bodyData
httpHeaders.forEach { request.addValue($0.value, forHTTPHeaderField: $0.key) }

let dataTask = session.dataTask(with: request) { data, _, error in
do {
guard let data = data else { throw error ?? ALTAppleAPIError(.unknown) }


let dataTask = self.session.dataTask(with: request) { (data, response, error) in
do
{
guard let data = data else { throw error ?? ALTAppleAPIError.unknown() }

guard let responseDictionary = try PropertyListSerialization.propertyList(from: data, format: nil) as? [String: Any],
let dictionary = responseDictionary["Response"] as? [String: Any],
let status = dictionary["Status"] as? [String: Any]
else { throw URLError(.badServerResponse) }

let errorCode = status["ec"] as? Int ?? 0
guard errorCode != 0 else { return completionHandler(.success(dictionary)) }

switch errorCode {

switch errorCode
{
case -20101, -22406: throw ALTAppleAPIError(.incorrectCredentials)
case -22421: throw ALTAppleAPIError(.invalidAnisetteData)
default:
guard let errorDescription = status["em"] as? String else { throw ALTAppleAPIError(.unknown) }

guard let errorDescription = status["em"] as? String else { throw ALTAppleAPIError.unknown() }
let localizedDescription = errorDescription + " (\(errorCode))"
throw ALTAppleAPIError(.unknown, userInfo: [NSLocalizedDescriptionKey: localizedDescription])
throw NSError(domain: ALTUnderlyingAppleAPIErrorDomain, code: errorCode, userInfo: [NSLocalizedDescriptionKey: localizedDescription])
}
} catch {
completionHandler(.failure(error))
Expand Down
8 changes: 4 additions & 4 deletions Sources/CAltSign/Apple API/ALTAppleAPI.m
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ - (void)addAppIDWithName:(NSString *)name bundleIdentifier:(NSString *)bundleIde
switch (resultCode)
{
case 35:
return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidAppIDName userInfo:nil];
return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorInvalidAppIDName userInfo:@{ALTAppNameErrorKey: sanitizedName}];

case 9120:
return [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorMaximumAppIDLimitReached userInfo:nil];
Expand Down Expand Up @@ -906,9 +906,9 @@ - (nullable id)processResponse:(NSDictionary *)responseDictionary
NSString *errorDescription = [responseDictionary objectForKey:@"userString"] ?: [responseDictionary objectForKey:@"resultString"];
NSString *localizedDescription = [NSString stringWithFormat:@"%@ (%@)", errorDescription, @(resultCode)];

NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[NSLocalizedDescriptionKey] = localizedDescription;
tempError = [NSError errorWithDomain:ALTAppleAPIErrorDomain code:ALTAppleAPIErrorUnknown userInfo:userInfo];
tempError = [NSError errorWithDomain:ALTUnderlyingAppleAPIErrorDomain code:resultCode userInfo:@{
NSLocalizedDescriptionKey: localizedDescription,
}];
}

*error = tempError;
Expand Down
52 changes: 29 additions & 23 deletions Sources/CAltSign/Categories/NSError+ALTErrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
#import <Foundation/Foundation.h>

extern NSErrorDomain const AltSignErrorDomain;
extern NSErrorDomain const ALTAppleAPIErrorDomain;
extern NSErrorDomain const ALTUnderlyingAppleAPIErrorDomain;

extern NSErrorUserInfoKey const ALTSourceFileErrorKey;
extern NSErrorUserInfoKey const ALTSourceLineErrorKey;
extern NSErrorUserInfoKey const ALTAppNameErrorKey;

typedef NS_ERROR_ENUM(AltSignErrorDomain, ALTError)
{
ALTErrorUnknown,
Expand All @@ -18,40 +25,39 @@ typedef NS_ERROR_ENUM(AltSignErrorDomain, ALTError)
ALTErrorMissingProvisioningProfile,
};

extern NSErrorDomain const ALTAppleAPIErrorDomain;
typedef NS_ERROR_ENUM(ALTAppleAPIErrorDomain, ALTAppleAPIError)
{
ALTAppleAPIErrorUnknown,
ALTAppleAPIErrorInvalidParameters,
ALTAppleAPIErrorUnknown = 3000,
ALTAppleAPIErrorInvalidParameters = 3001,

ALTAppleAPIErrorIncorrectCredentials,
ALTAppleAPIErrorAppSpecificPasswordRequired,
ALTAppleAPIErrorIncorrectCredentials = 3002,
ALTAppleAPIErrorAppSpecificPasswordRequired = 3003,

ALTAppleAPIErrorNoTeams,
ALTAppleAPIErrorNoTeams = 3004,

ALTAppleAPIErrorInvalidDeviceID,
ALTAppleAPIErrorDeviceAlreadyRegistered,
ALTAppleAPIErrorInvalidDeviceID = 3005,
ALTAppleAPIErrorDeviceAlreadyRegistered = 3006,

ALTAppleAPIErrorInvalidCertificateRequest,
ALTAppleAPIErrorCertificateDoesNotExist,
ALTAppleAPIErrorInvalidCertificateRequest = 3007,
ALTAppleAPIErrorCertificateDoesNotExist = 3008,

ALTAppleAPIErrorInvalidAppIDName,
ALTAppleAPIErrorInvalidBundleIdentifier,
ALTAppleAPIErrorBundleIdentifierUnavailable,
ALTAppleAPIErrorAppIDDoesNotExist,
ALTAppleAPIErrorMaximumAppIDLimitReached,
ALTAppleAPIErrorInvalidAppIDName = 3009,
ALTAppleAPIErrorInvalidBundleIdentifier = 3010,
ALTAppleAPIErrorBundleIdentifierUnavailable = 3011,
ALTAppleAPIErrorAppIDDoesNotExist = 3012,
ALTAppleAPIErrorMaximumAppIDLimitReached = 3013,

ALTAppleAPIErrorInvalidAppGroup,
ALTAppleAPIErrorAppGroupDoesNotExist,
ALTAppleAPIErrorInvalidAppGroup = 3014,
ALTAppleAPIErrorAppGroupDoesNotExist = 3015,

ALTAppleAPIErrorInvalidProvisioningProfileIdentifier,
ALTAppleAPIErrorProvisioningProfileDoesNotExist,
ALTAppleAPIErrorInvalidProvisioningProfileIdentifier = 3016,
ALTAppleAPIErrorProvisioningProfileDoesNotExist = 3017,

ALTAppleAPIErrorRequiresTwoFactorAuthentication,
ALTAppleAPIErrorIncorrectVerificationCode,
ALTAppleAPIErrorAuthenticationHandshakeFailed,
ALTAppleAPIErrorRequiresTwoFactorAuthentication = 3018,
ALTAppleAPIErrorIncorrectVerificationCode = 3019,
ALTAppleAPIErrorAuthenticationHandshakeFailed = 3020,

ALTAppleAPIErrorInvalidAnisetteData,
ALTAppleAPIErrorInvalidAnisetteData = 3021,
};

NS_ASSUME_NONNULL_BEGIN
Expand Down
79 changes: 72 additions & 7 deletions Sources/CAltSign/Categories/NSError+ALTErrors.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,36 @@

#import "NSError+ALTErrors.h"

NSErrorDomain const AltSignErrorDomain = @"com.rileytestut.AltSign";
NSErrorDomain const ALTAppleAPIErrorDomain = @"com.rileytestut.ALTAppleAPI";
NSErrorDomain const AltSignErrorDomain = @"AltSign.Error";
NSErrorDomain const ALTAppleAPIErrorDomain = @"AltStore.AppleDeveloperError";
NSErrorDomain const ALTUnderlyingAppleAPIErrorDomain = @"Apple.APIError";

NSErrorUserInfoKey const ALTSourceFileErrorKey = @"ALTSourceFile";
NSErrorUserInfoKey const ALTSourceLineErrorKey = @"ALTSourceLine";
NSErrorUserInfoKey const ALTAppNameErrorKey = @"appName";

@implementation NSError (ALTError)

+ (void)load
{
[NSError setUserInfoValueProviderForDomain:AltSignErrorDomain provider:^id _Nullable(NSError * _Nonnull error, NSErrorUserInfoKey _Nonnull userInfoKey) {
if ([userInfoKey isEqualToString:NSLocalizedFailureReasonErrorKey])
if ([userInfoKey isEqualToString:NSLocalizedDescriptionKey])
{
if ([error altsign_localizedFailure] != nil)
{
// Error has localizedFailure, so return nil to construct localizedDescription from it + localizedFailureReason.
return nil;
}
else
{
// Otherwise, return failureReason for localizedDescription to avoid system prepending "Operation Failed" message.
// Do NOT return [error alt_localizedFailureReason], which might be unexpectedly nil if unrecognized error code.
return error.localizedFailureReason;
}
}
else if ([userInfoKey isEqualToString:NSLocalizedFailureReasonErrorKey])
{
// Return failureReason for both keys to prevent prepending "Operation Failed" message to localizedDescription.
return [error alt_localizedFailureReason];
}

Expand All @@ -27,7 +47,22 @@ + (void)load
[NSError setUserInfoValueProviderForDomain:ALTAppleAPIErrorDomain provider:^id _Nullable(NSError * _Nonnull error, NSErrorUserInfoKey _Nonnull userInfoKey) {
if ([userInfoKey isEqualToString:NSLocalizedDescriptionKey])
{
return [error alt_appleapi_localizedDescription];
if ([error altsign_localizedFailure] != nil)
{
// Error has localizedFailure, so return nil to construct localizedDescription from it + localizedFailureReason.
return nil;
}
else
{
// Otherwise, return failureReason for localizedDescription to avoid system prepending "Operation Failed" message.
// Do NOT return [error alt_appleapi_localizedFailureReason], which might be unexpectedly nil if unrecognized error code.
return error.localizedFailureReason;
}
}
else if ([userInfoKey isEqualToString:NSLocalizedFailureReasonErrorKey])
{
// Return failureReason for both keys to prevent prepending "Operation Failed" message to localizedDescription.
return [error alt_appleapi_localizedFailureReason];
}
else if ([userInfoKey isEqualToString:NSLocalizedRecoverySuggestionErrorKey])
{
Expand All @@ -38,6 +73,25 @@ + (void)load
}];
}

- (nullable NSString *)altsign_localizedFailure
{
// Copied logic from AltStore's NSError+AltStore.swift.
NSString *localizedFailure = self.userInfo[NSLocalizedFailureErrorKey];
if (localizedFailure != nil)
{
return localizedFailure;
}

id (^provider)(NSError *, NSErrorUserInfoKey) = [NSError userInfoValueProviderForDomain:self.domain];
if (provider == nil)
{
return nil;
}

localizedFailure = provider(self, NSLocalizedFailureErrorKey);
return localizedFailure;
}

- (nullable NSString *)alt_localizedFailureReason
{
switch ((ALTError)self.code)
Expand All @@ -61,7 +115,7 @@ - (nullable NSString *)alt_localizedFailureReason
return nil;
}

- (nullable NSString *)alt_appleapi_localizedDescription
- (nullable NSString *)alt_appleapi_localizedFailureReason
{
switch ((ALTAppleAPIError)self.code)
{
Expand All @@ -72,7 +126,7 @@ - (nullable NSString *)alt_appleapi_localizedDescription
return NSLocalizedString(@"The provided parameters are invalid.", @"");

case ALTAppleAPIErrorIncorrectCredentials:
return NSLocalizedString(@"Incorrect Apple ID or password.", @"");
return NSLocalizedString(@"Your Apple ID or password is incorrect.", @"");

case ALTAppleAPIErrorNoTeams:
return NSLocalizedString(@"You are not a member of any development teams.", @"");
Expand All @@ -93,7 +147,15 @@ - (nullable NSString *)alt_appleapi_localizedDescription
return NSLocalizedString(@"There is no certificate with the requested serial number for this team.", @"");

case ALTAppleAPIErrorInvalidAppIDName:
return NSLocalizedString(@"The name for this app is invalid.", @"");
{
NSString *appName = self.userInfo[ALTAppNameErrorKey];
if (appName != nil)
{
return [NSString stringWithFormat:NSLocalizedString(@"The name “%@” contains invalid characters.", @""), appName];
}

return NSLocalizedString(@"The name of this app contains invalid characters.", @"");
}

case ALTAppleAPIErrorInvalidBundleIdentifier:
return NSLocalizedString(@"The bundle identifier for this app is invalid.", @"");
Expand Down Expand Up @@ -139,6 +201,9 @@ - (nullable NSString *)alt_appleapi_localizedRecoverySuggestion
{
switch ((ALTAppleAPIError)self.code)
{
case ALTAppleAPIErrorIncorrectCredentials:
return NSLocalizedString(@"Please make sure you entered both your Apple ID and password correctly and try again.", @"");

case ALTAppleAPIErrorInvalidAnisetteData:
#if TARGET_OS_OSX
return NSLocalizedString(@"Make sure this computer's date & time matches your iOS device and try again.", @"");
Expand Down
8 changes: 6 additions & 2 deletions Sources/CAltSign/Signing/ALTSigner.mm
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ - (NSProgress *)signAppAtURL:(NSURL *)appURL provisioningProfiles:(NSArray<ALTPr
}

for (ALTApplication *appExtension in application.appExtensions)
{
{
NSError *error = prepareApp(appExtension);
if (error != nil)
{
Expand Down Expand Up @@ -474,7 +474,11 @@ - (NSProgress *)signAppAtURL:(NSURL *)appURL provisioningProfiles:(NSArray<ALTPr
}
catch (std::exception& exception)
{
NSError *error = [NSError errorWithDomain:AltSignErrorDomain code:ALTErrorUnknown userInfo:@{NSLocalizedDescriptionKey: @(exception.what())}];
NSError *error = [NSError errorWithDomain:AltSignErrorDomain code:ALTErrorUnknown userInfo:@{
NSLocalizedFailureReasonErrorKey: @(exception.what()),
ALTSourceFileErrorKey: @(__FILE__).lastPathComponent,
ALTSourceLineErrorKey: @(__LINE__)
}];
finish(NO, error);
}
});
Expand Down

0 comments on commit 74c9572

Please sign in to comment.