Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- Merge-Upstream: Rebased recent commits from rileytestut/AltSign - possibly removes need for 2FA code on iOS 18.1+ #3

Merged
merged 11 commits into from
Nov 30, 2024
Merged
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
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
Loading