Replace local code with updated Roxas and SideKit

Signed-off-by: Joseph Mattello <mail@joemattiello.com>
This commit is contained in:
Joseph Mattello
2023-02-25 01:37:52 -05:00
committed by Joe Mattiello
parent 4e84dc4cc8
commit f270ecc537
14 changed files with 124 additions and 1200 deletions

View File

@@ -1,72 +0,0 @@
//
// NSError+ALTServerError.h
// AltStore
//
// Created by Riley Testut on 5/30/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSErrorDomain const AltServerErrorDomain;
extern NSErrorDomain const AltServerInstallationErrorDomain;
extern NSErrorDomain const AltServerConnectionErrorDomain;
extern NSErrorUserInfoKey const ALTUnderlyingErrorDomainErrorKey;
extern NSErrorUserInfoKey const ALTUnderlyingErrorCodeErrorKey;
extern NSErrorUserInfoKey const ALTProvisioningProfileBundleIDErrorKey;
extern NSErrorUserInfoKey const ALTAppNameErrorKey;
extern NSErrorUserInfoKey const ALTDeviceNameErrorKey;
extern NSErrorUserInfoKey const ALTOperatingSystemNameErrorKey;
extern NSErrorUserInfoKey const ALTOperatingSystemVersionErrorKey;
typedef NS_ERROR_ENUM(AltServerErrorDomain, ALTServerError)
{
ALTServerErrorUnderlyingError = -1,
ALTServerErrorUnknown = 0,
ALTServerErrorConnectionFailed = 1,
ALTServerErrorLostConnection = 2,
ALTServerErrorDeviceNotFound = 3,
ALTServerErrorDeviceWriteFailed = 4,
ALTServerErrorInvalidRequest = 5,
ALTServerErrorInvalidResponse = 6,
ALTServerErrorInvalidApp = 7,
ALTServerErrorInstallationFailed = 8,
ALTServerErrorMaximumFreeAppLimitReached = 9,
ALTServerErrorUnsupportediOSVersion = 10,
ALTServerErrorUnknownRequest = 11,
ALTServerErrorUnknownResponse = 12,
ALTServerErrorInvalidAnisetteData = 13,
ALTServerErrorPluginNotFound = 14,
ALTServerErrorProfileNotFound = 15,
ALTServerErrorAppDeletionFailed = 16,
ALTServerErrorRequestedAppNotRunning = 100,
ALTServerErrorIncompatibleDeveloperDisk = 101
};
typedef NS_ERROR_ENUM(AltServerConnectionErrorDomain, ALTServerConnectionError)
{
ALTServerConnectionErrorUnknown,
ALTServerConnectionErrorDeviceLocked,
ALTServerConnectionErrorInvalidRequest,
ALTServerConnectionErrorInvalidResponse,
ALTServerConnectionErrorUsbmuxd,
ALTServerConnectionErrorSSL,
ALTServerConnectionErrorTimedOut,
};
NS_ASSUME_NONNULL_BEGIN
@interface NSError (ALTServerError)
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,316 +0,0 @@
//
// NSError+ALTServerError.m
// AltStore
//
// Created by Riley Testut on 5/30/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
#import "NSError+ALTServerError.h"
NSErrorDomain const AltServerErrorDomain = @"com.rileytestut.AltServer";
NSErrorDomain const AltServerInstallationErrorDomain = @"com.rileytestut.AltServer.Installation";
NSErrorDomain const AltServerConnectionErrorDomain = @"com.rileytestut.AltServer.Connection";
NSErrorUserInfoKey const ALTUnderlyingErrorDomainErrorKey = @"underlyingErrorDomain";
NSErrorUserInfoKey const ALTUnderlyingErrorCodeErrorKey = @"underlyingErrorCode";
NSErrorUserInfoKey const ALTProvisioningProfileBundleIDErrorKey = @"bundleIdentifier";
NSErrorUserInfoKey const ALTAppNameErrorKey = @"appName";
NSErrorUserInfoKey const ALTDeviceNameErrorKey = @"deviceName";
NSErrorUserInfoKey const ALTOperatingSystemNameErrorKey = @"ALTOperatingSystemName";
NSErrorUserInfoKey const ALTOperatingSystemVersionErrorKey = @"ALTOperatingSystemVersion";
@implementation NSError (ALTServerError)
+ (void)load
{
[NSError setUserInfoValueProviderForDomain:AltServerErrorDomain provider:^id _Nullable(NSError * _Nonnull error, NSErrorUserInfoKey _Nonnull userInfoKey) {
if ([userInfoKey isEqualToString:NSLocalizedFailureReasonErrorKey])
{
return [error altserver_localizedFailureReason];
}
else if ([userInfoKey isEqualToString:NSLocalizedRecoverySuggestionErrorKey])
{
return [error altserver_localizedRecoverySuggestion];
}
else if ([userInfoKey isEqualToString:NSDebugDescriptionErrorKey])
{
return [error altserver_localizedDebugDescription];
}
return nil;
}];
[NSError setUserInfoValueProviderForDomain:AltServerConnectionErrorDomain provider:^id _Nullable(NSError * _Nonnull error, NSErrorUserInfoKey _Nonnull userInfoKey) {
if ([userInfoKey isEqualToString:NSLocalizedDescriptionKey])
{
return [error altserver_connection_localizedDescription];
}
else if ([userInfoKey isEqualToString:NSLocalizedRecoverySuggestionErrorKey])
{
return [error altserver_connection_localizedRecoverySuggestion];
}
return nil;
}];
}
- (nullable NSString *)altserver_localizedFailureReason
{
switch ((ALTServerError)self.code)
{
case ALTServerErrorUnderlyingError:
{
NSError *underlyingError = self.userInfo[NSUnderlyingErrorKey];
if (underlyingError.localizedFailureReason != nil)
{
return underlyingError.localizedFailureReason;
}
NSString *underlyingErrorCode = self.userInfo[ALTUnderlyingErrorCodeErrorKey];
if (underlyingErrorCode != nil)
{
return [NSString stringWithFormat:NSLocalizedString(@"Error code: %@", @""), underlyingErrorCode];
}
return nil;
}
case ALTServerErrorUnknown:
return NSLocalizedString(@"An unknown error occured.", @"");
case ALTServerErrorConnectionFailed:
#if TARGET_OS_OSX
return NSLocalizedString(@"There was an error connecting to the device.", @"");
#else
return NSLocalizedString(@"Could not connect to SideStore.", @"");
#endif
case ALTServerErrorLostConnection:
return NSLocalizedString(@"Lost connection to SideStore.", @"");
case ALTServerErrorDeviceNotFound:
return NSLocalizedString(@"SideStore could not find this device.", @"");
case ALTServerErrorDeviceWriteFailed:
return NSLocalizedString(@"Failed to write app data to device.", @"");
case ALTServerErrorInvalidRequest:
return NSLocalizedString(@"SideStore received an invalid request.", @"");
case ALTServerErrorInvalidResponse:
return NSLocalizedString(@"SideStore sent an invalid response.", @"");
case ALTServerErrorInvalidApp:
return NSLocalizedString(@"The app is invalid.", @"");
case ALTServerErrorInstallationFailed:
return NSLocalizedString(@"An error occured while installing the app.", @"");
case ALTServerErrorMaximumFreeAppLimitReached:
return NSLocalizedString(@"Cannot activate more than 3 apps with a non-developer Apple ID.", @"");
case ALTServerErrorUnsupportediOSVersion:
return NSLocalizedString(@"Your device must be running iOS 12.2 or later to install SideStore.", @"");
case ALTServerErrorUnknownRequest:
return NSLocalizedString(@"SideStore does not support this request.", @"");
case ALTServerErrorUnknownResponse:
return NSLocalizedString(@"Received an unknown response from SideStore.", @"");
case ALTServerErrorInvalidAnisetteData:
return NSLocalizedString(@"The provided anisette data is invalid.", @"");
case ALTServerErrorPluginNotFound:
return NSLocalizedString(@"AltServer could not connect to Mail plug-in.", @"");
case ALTServerErrorProfileNotFound:
return [self profileErrorLocalizedDescriptionWithBaseDescription:NSLocalizedString(@"Could not find profile", "")];
case ALTServerErrorAppDeletionFailed:
return NSLocalizedString(@"An error occured while removing the app.", @"");
case ALTServerErrorRequestedAppNotRunning:
{
NSString *appName = self.userInfo[ALTAppNameErrorKey] ?: NSLocalizedString(@"The requested app", @"");
NSString *deviceName = self.userInfo[ALTDeviceNameErrorKey] ?: NSLocalizedString(@"the device", @"");
return [NSString stringWithFormat:NSLocalizedString(@"%@ is not currently running on %@.", ""), appName, deviceName];
}
case ALTServerErrorIncompatibleDeveloperDisk:
{
NSString *osVersion = [self altserver_osVersion] ?: NSLocalizedString(@"this device's OS version", @"");
NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"The disk is incompatible with %@.", @""), osVersion];
return failureReason;
}
}
return nil;
}
- (nullable NSString *)altserver_localizedRecoverySuggestion
{
switch ((ALTServerError)self.code)
{
case ALTServerErrorConnectionFailed:
case ALTServerErrorDeviceNotFound:
return NSLocalizedString(@"Make sure you have trusted this device with your computer and Wi-Fi sync is enabled.", @"");
case ALTServerErrorPluginNotFound:
return NSLocalizedString(@"Mail has been automatically opened, try again in a moment. Otherwise, make sure plug-in is enabled in Mail's preferences.", @"");
case ALTServerErrorMaximumFreeAppLimitReached:
#if TARGET_OS_OSX
return NSLocalizedString(@"Please deactivate a sideloaded app with SideStore in order to install another app.\n\nIf you're running iOS 13.5 or later, make sure 'Offload Unused Apps' is disabled in Settings > iTunes & App Stores, then install or delete all offloaded apps to prevent them from erroneously counting towards this limit.", @"");
#else
return NSLocalizedString(@"Please deactivate a sideloaded app in order to install another one.\n\nIf you're running iOS 13.5 or later, make sure “Offload Unused Apps” is disabled in Settings > iTunes & App Stores, then install or delete all offloaded apps.", @"");
#endif
case ALTServerErrorRequestedAppNotRunning:
{
NSString *deviceName = self.userInfo[ALTDeviceNameErrorKey] ?: NSLocalizedString(@"your device", @"");
return [NSString stringWithFormat:NSLocalizedString(@"Make sure the app is running in the foreground on %@ then try again.", @""), deviceName];
}
default:
return nil;
}
}
- (nullable NSString *)altserver_localizedDebugDescription
{
switch ((ALTServerError)self.code)
{
case ALTServerErrorIncompatibleDeveloperDisk:
{
NSString *path = self.userInfo[NSFilePathErrorKey];
if (path == nil)
{
return nil;
}
NSString *osVersion = [self altserver_osVersion] ?: NSLocalizedString(@"this device's OS version", @"");
NSString *debugDescription = [NSString stringWithFormat:NSLocalizedString(@"The Developer disk located at\n\n%@\n\nis incompatible with %@.", @""), path, osVersion];
return debugDescription;
}
default:
return nil;
}
}
- (NSString *)profileErrorLocalizedDescriptionWithBaseDescription:(NSString *)baseDescription
{
NSString *localizedDescription = nil;
NSString *bundleID = self.userInfo[ALTProvisioningProfileBundleIDErrorKey];
if (bundleID)
{
localizedDescription = [NSString stringWithFormat:@"%@ “%@”", baseDescription, bundleID];
}
else
{
localizedDescription = [NSString stringWithFormat:@"%@.", baseDescription];
}
return localizedDescription;
}
- (nullable NSString *)altserver_osVersion
{
NSString *osName = self.userInfo[ALTOperatingSystemNameErrorKey];
NSString *versionString = self.userInfo[ALTOperatingSystemVersionErrorKey];
if (osName == nil || versionString == nil)
{
return nil;
}
NSString *osVersion = [NSString stringWithFormat:@"%@ %@", osName, versionString];
return osVersion;
}
#pragma mark - AltServerConnectionErrorDomain -
- (nullable NSString *)altserver_connection_localizedDescription
{
switch ((ALTServerConnectionError)self.code)
{
case ALTServerConnectionErrorUnknown:
{
NSString *underlyingErrorDomain = self.userInfo[ALTUnderlyingErrorDomainErrorKey];
NSString *underlyingErrorCode = self.userInfo[ALTUnderlyingErrorCodeErrorKey];
if (underlyingErrorDomain != nil && underlyingErrorCode != nil)
{
return [NSString stringWithFormat:NSLocalizedString(@"%@ error %@.", @""), underlyingErrorDomain, underlyingErrorCode];
}
else if (underlyingErrorCode != nil)
{
return [NSString stringWithFormat:NSLocalizedString(@"Connection error code: %@", @""), underlyingErrorCode];
}
return nil;
}
case ALTServerConnectionErrorDeviceLocked:
{
NSString *deviceName = self.userInfo[ALTDeviceNameErrorKey] ?: NSLocalizedString(@"The device", @"");
return [NSString stringWithFormat:NSLocalizedString(@"%@ is currently locked.", @""), deviceName];
}
case ALTServerConnectionErrorInvalidRequest:
{
NSString *deviceName = self.userInfo[ALTDeviceNameErrorKey] ?: NSLocalizedString(@"The device", @"");
return [NSString stringWithFormat:NSLocalizedString(@"%@ received an invalid request from SideStore.", @""), deviceName];
}
case ALTServerConnectionErrorInvalidResponse:
{
NSString *deviceName = self.userInfo[ALTDeviceNameErrorKey] ?: NSLocalizedString(@"the device", @"");
return [NSString stringWithFormat:NSLocalizedString(@"SideStore received an invalid response from %@.", @""), deviceName];
}
case ALTServerConnectionErrorUsbmuxd:
{
return NSLocalizedString(@"There was an issue communicating with the usbmuxd daemon.", @"");
}
case ALTServerConnectionErrorSSL:
{
NSString *deviceName = self.userInfo[ALTDeviceNameErrorKey] ?: NSLocalizedString(@"the device", @"");
return [NSString stringWithFormat:NSLocalizedString(@"SideStore could not establish a secure connection to %@.", @""), deviceName];
}
case ALTServerConnectionErrorTimedOut:
{
NSString *deviceName = self.userInfo[ALTDeviceNameErrorKey] ?: NSLocalizedString(@"the device", @"");
return [NSString stringWithFormat:NSLocalizedString(@"SideStore's connection to %@ timed out.", @""), deviceName];
}
}
return nil;
}
- (nullable NSString *)altserver_connection_localizedRecoverySuggestion
{
switch ((ALTServerConnectionError)self.code)
{
case ALTServerConnectionErrorDeviceLocked:
{
return NSLocalizedString(@"Please unlock the device with your passcode and try again.", @"");
}
case ALTServerConnectionErrorUnknown:
case ALTServerConnectionErrorInvalidRequest:
case ALTServerConnectionErrorInvalidResponse:
case ALTServerConnectionErrorUsbmuxd:
case ALTServerConnectionErrorSSL:
case ALTServerConnectionErrorTimedOut:
{
return nil;
}
}
}
@end

View File

@@ -1,23 +0,0 @@
//
// ALTConnection.h
// AltKit
//
// Created by Riley Testut on 6/1/20.
// Copyright © 2020 Riley Testut. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(Connection)
@protocol ALTConnection <NSObject>
- (void)sendData:(NSData *)data completionHandler:(void (^)(BOOL, NSError * _Nullable))completionHandler NS_REFINED_FOR_SWIFT;
- (void)receiveDataWithExpectedSize:(NSInteger)expectedSize completionHandler:(void (^)(NSData * _Nullable, NSError * _Nullable))completionHandler NS_SWIFT_NAME(__receiveData(expectedSize:completionHandler:));
- (void)disconnect;
@end
NS_ASSUME_NONNULL_END

View File

@@ -8,17 +8,19 @@
import Foundation
import Network
import SideKit
public extension Connection
{
func send(_ data: Data, completionHandler: @escaping (Result<Void, ALTServerError>) -> Void)
{
self.__send(data) { (success, error) in
let result = Result(success, error).mapError { (error) -> ALTServerError in
guard let nwError = error as? NWError else { return ALTServerError(error) }
return ALTServerError(.lostConnection, underlyingError: nwError)
let result = Result(success, error).mapError { (failure :Error) -> ALTServerError in
guard let nwError = failure as? NWError else { return ALTServerError.init(failure) }
return ALTServerError.lostConnection(underlyingError: nwError)
}
completionHandler(result)
}
}
@@ -26,9 +28,9 @@ public extension Connection
func receiveData(expectedSize: Int, completionHandler: @escaping (Result<Data, ALTServerError>) -> Void)
{
self.__receiveData(expectedSize: expectedSize) { (data, error) in
let result = Result(data, error).mapError { (error) -> ALTServerError in
guard let nwError = error as? NWError else { return ALTServerError(error) }
return ALTServerError(.lostConnection, underlyingError: nwError)
let result = Result(data, error).mapError { (failure :Error) -> ALTServerError in
guard let nwError = failure as? NWError else { return ALTServerError.init(failure) }
return ALTServerError.lostConnection(underlyingError: nwError)
}
completionHandler(result)
@@ -72,7 +74,7 @@ public extension Connection
}
catch
{
finish(.failure(.init(.invalidResponse, underlyingError: error)))
finish(.failure(.invalidResponse(underlyingError: error)))
}
}

View File

@@ -8,6 +8,7 @@
import Foundation
import Network
import SideKit
public protocol RequestHandler
{
@@ -26,24 +27,25 @@ public protocol RequestHandler
public protocol ConnectionHandler: AnyObject
{
var connectionHandler: ((Connection) -> Void)? { get set }
var disconnectionHandler: ((Connection) -> Void)? { get set }
associatedtype ConnectionType = Connection
var connectionHandler: ((ConnectionType) -> Void)? { get set }
var disconnectionHandler: ((ConnectionType) -> Void)? { get set }
func startListening()
func stopListening()
}
public class ConnectionManager<RequestHandlerType: RequestHandler>
public class ConnectionManager<RequestHandlerType: RequestHandler, ConnectionType: NetworkConnection & AnyObject, ConnectionHandlerType: ConnectionHandler> where ConnectionHandlerType.ConnectionType == ConnectionType
{
public let requestHandler: RequestHandlerType
public let connectionHandlers: [ConnectionHandler]
public let connectionHandlers: [ConnectionHandlerType]
public var isStarted = false
private var connections = [Connection]()
private var connections = [ConnectionType]()
private let connectionsLock = NSLock()
public init(requestHandler: RequestHandlerType, connectionHandlers: [ConnectionHandler])
public init(requestHandler: RequestHandlerType, connectionHandlers: [ConnectionHandlerType])
{
self.requestHandler = requestHandler
self.connectionHandlers = connectionHandlers
@@ -87,7 +89,7 @@ public class ConnectionManager<RequestHandlerType: RequestHandler>
private extension ConnectionManager
{
func prepare(_ connection: Connection)
func prepare(_ connection: ConnectionType)
{
self.connectionsLock.lock()
defer { self.connectionsLock.unlock() }
@@ -98,7 +100,7 @@ private extension ConnectionManager
self.handleRequest(for: connection)
}
func disconnect(_ connection: Connection)
func disconnect(_ connection: ConnectionType)
{
self.connectionsLock.lock()
defer { self.connectionsLock.unlock() }
@@ -107,7 +109,7 @@ private extension ConnectionManager
self.connections.remove(at: index)
}
func handleRequest(for connection: Connection)
func handleRequest(for connection: ConnectionType)
{
func finish<T: ServerMessageProtocol>(_ result: Result<T, Error>)
{
@@ -167,7 +169,7 @@ private extension ConnectionManager
}
case .success(.unknown):
finish(Result<ErrorResponse, Error>.failure(ALTServerError(.unknownRequest)))
finish(Result<ErrorResponse, Error>.failure(ALTServerError.unknownRequest))
}
}
}

View File

@@ -8,6 +8,7 @@
import Foundation
import Network
import SideKit
public class NetworkConnection: NSObject, Connection
{
@@ -29,7 +30,7 @@ public class NetworkConnection: NSObject, Connection
{
self.nwConnection.receive(minimumIncompleteLength: expectedSize, maximumLength: expectedSize) { (data, context, isComplete, error) in
guard data != nil || error != nil else {
return completionHandler(nil, ALTServerError(.lostConnection))
return completionHandler(nil, ALTServerError.lostConnection(underlyingError: error))
}
completionHandler(data, error)

View File

@@ -7,6 +7,7 @@
//
import Foundation
import SideKit
@objc private protocol XPCConnectionProxy
{
@@ -44,7 +45,7 @@ public class XPCConnection: NSObject, Connection
super.init()
xpcConnection.interruptionHandler = {
self.error = ALTServerError(.lostConnection)
self.error = ALTServerError.lostConnection(underlyingError: nil)
}
xpcConnection.exportedObject = self

View File

@@ -1,39 +0,0 @@
//
// ALTServerError+Conveniences.swift
// AltKit
//
// Created by Riley Testut on 6/4/20.
// Copyright © 2020 Riley Testut. All rights reserved.
//
import Foundation
import AltSign
public extension ALTServerError
{
init<E: Error>(_ error: E)
{
switch error
{
case let error as ALTServerError: self = error
case let error as ALTServerConnectionError: self = ALTServerError(.connectionFailed, underlyingError: error)
case let error as ALTAppleAPIError where error.code == .invalidAnisetteData: self = ALTServerError(.invalidAnisetteData, underlyingError: error)
case is DecodingError: self = ALTServerError(.invalidRequest, underlyingError: error)
case is EncodingError: self = ALTServerError(.invalidResponse, underlyingError: error)
case let error as NSError:
var userInfo = error.userInfo
if !userInfo.keys.contains(NSUnderlyingErrorKey)
{
// Assign underlying error (if there isn't already one).
userInfo[NSUnderlyingErrorKey] = error
}
self = ALTServerError(.underlyingError, userInfo: userInfo)
}
}
init<E: Error>(_ code: ALTServerError.Code, underlyingError: E)
{
self = ALTServerError(code, userInfo: [NSUnderlyingErrorKey: underlyingError])
}
}

View File

@@ -1,126 +0,0 @@
//
// CodableServerError.swift
// AltKit
//
// Created by Riley Testut on 3/5/20.
// Copyright © 2020 Riley Testut. All rights reserved.
//
import Foundation
// Can only automatically conform ALTServerError.Code to Codable, not ALTServerError itself
extension ALTServerError.Code: Codable {}
extension CodableServerError
{
enum UserInfoValue: Codable
{
case string(String)
case error(NSError)
public init(from decoder: Decoder) throws
{
let container = try decoder.singleValueContainer()
if
let data = try? container.decode(Data.self),
let error = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NSError.self, from: data)
{
self = .error(error)
}
else if let string = try? container.decode(String.self)
{
self = .string(string)
}
else
{
throw DecodingError.dataCorruptedError(in: container, debugDescription: "UserInfoValue value cannot be decoded")
}
}
func encode(to encoder: Encoder) throws
{
var container = encoder.singleValueContainer()
switch self
{
case .string(let string): try container.encode(string)
case .error(let error):
guard let data = try? NSKeyedArchiver.archivedData(withRootObject: error, requiringSecureCoding: true) else {
let context = EncodingError.Context(codingPath: container.codingPath, debugDescription: "UserInfoValue value \(self) cannot be encoded")
throw EncodingError.invalidValue(self, context)
}
try container.encode(data)
}
}
}
}
struct CodableServerError: Codable
{
var error: ALTServerError {
return ALTServerError(self.errorCode, userInfo: self.userInfo ?? [:])
}
private var errorCode: ALTServerError.Code
private var userInfo: [String: Any]?
private enum CodingKeys: String, CodingKey
{
case errorCode
case userInfo
}
init(error: ALTServerError)
{
self.errorCode = error.code
var userInfo = error.userInfo
if let localizedRecoverySuggestion = (error as NSError).localizedRecoverySuggestion
{
userInfo[NSLocalizedRecoverySuggestionErrorKey] = localizedRecoverySuggestion
}
if !userInfo.isEmpty
{
self.userInfo = userInfo
}
}
init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
let errorCode = try container.decode(Int.self, forKey: .errorCode)
self.errorCode = ALTServerError.Code(rawValue: errorCode) ?? .unknown
let rawUserInfo = try container.decodeIfPresent([String: UserInfoValue].self, forKey: .userInfo)
let userInfo = rawUserInfo?.mapValues { (value) -> Any in
switch value
{
case .string(let string): return string
case .error(let error): return error
}
}
self.userInfo = userInfo
}
func encode(to encoder: Encoder) throws
{
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.error.code.rawValue, forKey: .errorCode)
let rawUserInfo = self.userInfo?.compactMapValues { (value) -> UserInfoValue? in
switch value
{
case let string as String: return .string(string)
case let error as NSError: return .error(error)
default: return nil
}
}
try container.encodeIfPresent(rawUserInfo, forKey: .userInfo)
}
}

View File

@@ -1,472 +0,0 @@
//
// ServerProtocol.swift
// AltServer
//
// Created by Riley Testut on 5/24/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
import Foundation
import AltSign
public let ALTServerServiceType = "_altserver._tcp"
protocol ServerMessageProtocol: Codable
{
var version: Int { get }
var identifier: String { get }
}
public enum ServerRequest: Decodable
{
case anisetteData(AnisetteDataRequest)
case prepareApp(PrepareAppRequest)
case beginInstallation(BeginInstallationRequest)
case installProvisioningProfiles(InstallProvisioningProfilesRequest)
case removeProvisioningProfiles(RemoveProvisioningProfilesRequest)
case removeApp(RemoveAppRequest)
case enableUnsignedCodeExecution(EnableUnsignedCodeExecutionRequest)
case unknown(identifier: String, version: Int)
var identifier: String {
switch self
{
case .anisetteData(let request): return request.identifier
case .prepareApp(let request): return request.identifier
case .beginInstallation(let request): return request.identifier
case .installProvisioningProfiles(let request): return request.identifier
case .removeProvisioningProfiles(let request): return request.identifier
case .removeApp(let request): return request.identifier
case .enableUnsignedCodeExecution(let request): return request.identifier
case .unknown(let identifier, _): return identifier
}
}
var version: Int {
switch self
{
case .anisetteData(let request): return request.version
case .prepareApp(let request): return request.version
case .beginInstallation(let request): return request.version
case .installProvisioningProfiles(let request): return request.version
case .removeProvisioningProfiles(let request): return request.version
case .removeApp(let request): return request.version
case .enableUnsignedCodeExecution(let request): return request.version
case .unknown(_, let version): return version
}
}
private enum CodingKeys: String, CodingKey
{
case identifier
case version
}
public init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
let version = try container.decode(Int.self, forKey: .version)
let identifier = try container.decode(String.self, forKey: .identifier)
switch identifier
{
case "AnisetteDataRequest":
let request = try AnisetteDataRequest(from: decoder)
self = .anisetteData(request)
case "PrepareAppRequest":
let request = try PrepareAppRequest(from: decoder)
self = .prepareApp(request)
case "BeginInstallationRequest":
let request = try BeginInstallationRequest(from: decoder)
self = .beginInstallation(request)
case "InstallProvisioningProfilesRequest":
let request = try InstallProvisioningProfilesRequest(from: decoder)
self = .installProvisioningProfiles(request)
case "RemoveProvisioningProfilesRequest":
let request = try RemoveProvisioningProfilesRequest(from: decoder)
self = .removeProvisioningProfiles(request)
case "RemoveAppRequest":
let request = try RemoveAppRequest(from: decoder)
self = .removeApp(request)
case "EnableUnsignedCodeExecutionRequest":
let request = try EnableUnsignedCodeExecutionRequest(from: decoder)
self = .enableUnsignedCodeExecution(request)
default:
self = .unknown(identifier: identifier, version: version)
}
}
}
public enum ServerResponse: Decodable
{
case anisetteData(AnisetteDataResponse)
case installationProgress(InstallationProgressResponse)
case installProvisioningProfiles(InstallProvisioningProfilesResponse)
case removeProvisioningProfiles(RemoveProvisioningProfilesResponse)
case removeApp(RemoveAppResponse)
case enableUnsignedCodeExecution(EnableUnsignedCodeExecutionResponse)
case error(ErrorResponse)
case unknown(identifier: String, version: Int)
var identifier: String {
switch self
{
case .anisetteData(let response): return response.identifier
case .installationProgress(let response): return response.identifier
case .installProvisioningProfiles(let response): return response.identifier
case .removeProvisioningProfiles(let response): return response.identifier
case .removeApp(let response): return response.identifier
case .enableUnsignedCodeExecution(let response): return response.identifier
case .error(let response): return response.identifier
case .unknown(let identifier, _): return identifier
}
}
var version: Int {
switch self
{
case .anisetteData(let response): return response.version
case .installationProgress(let response): return response.version
case .installProvisioningProfiles(let response): return response.version
case .removeProvisioningProfiles(let response): return response.version
case .removeApp(let response): return response.version
case .enableUnsignedCodeExecution(let response): return response.version
case .error(let response): return response.version
case .unknown(_, let version): return version
}
}
private enum CodingKeys: String, CodingKey
{
case identifier
case version
}
public init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
let version = try container.decode(Int.self, forKey: .version)
let identifier = try container.decode(String.self, forKey: .identifier)
switch identifier
{
case "AnisetteDataResponse":
let response = try AnisetteDataResponse(from: decoder)
self = .anisetteData(response)
case "InstallationProgressResponse":
let response = try InstallationProgressResponse(from: decoder)
self = .installationProgress(response)
case "InstallProvisioningProfilesResponse":
let response = try InstallProvisioningProfilesResponse(from: decoder)
self = .installProvisioningProfiles(response)
case "RemoveProvisioningProfilesResponse":
let response = try RemoveProvisioningProfilesResponse(from: decoder)
self = .removeProvisioningProfiles(response)
case "RemoveAppResponse":
let response = try RemoveAppResponse(from: decoder)
self = .removeApp(response)
case "EnableUnsignedCodeExecutionResponse":
let response = try EnableUnsignedCodeExecutionResponse(from: decoder)
self = .enableUnsignedCodeExecution(response)
case "ErrorResponse":
let response = try ErrorResponse(from: decoder)
self = .error(response)
default:
self = .unknown(identifier: identifier, version: version)
}
}
}
// _Don't_ provide generic SuccessResponse, as that would prevent us
// from easily changing response format for a request in the future.
public struct ErrorResponse: ServerMessageProtocol
{
public var version = 2
public var identifier = "ErrorResponse"
public var error: ALTServerError {
return self.serverError?.error ?? ALTServerError(self.errorCode)
}
private var serverError: CodableServerError?
// Legacy (v1)
private var errorCode: ALTServerError.Code
public init(error: ALTServerError)
{
self.serverError = CodableServerError(error: error)
self.errorCode = error.code
}
}
public struct AnisetteDataRequest: ServerMessageProtocol
{
public var version = 1
public var identifier = "AnisetteDataRequest"
public init()
{
}
}
public struct AnisetteDataResponse: ServerMessageProtocol
{
public var version = 1
public var identifier = "AnisetteDataResponse"
public var anisetteData: ALTAnisetteData
private enum CodingKeys: String, CodingKey
{
case identifier
case version
case anisetteData
}
public init(anisetteData: ALTAnisetteData)
{
self.anisetteData = anisetteData
}
public init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
self.version = try container.decode(Int.self, forKey: .version)
self.identifier = try container.decode(String.self, forKey: .identifier)
let json = try container.decode([String: String].self, forKey: .anisetteData)
if let anisetteData = ALTAnisetteData(json: json)
{
self.anisetteData = anisetteData
}
else
{
throw DecodingError.dataCorruptedError(forKey: CodingKeys.anisetteData, in: container, debugDescription: "Couuld not parse anisette data from JSON")
}
}
public func encode(to encoder: Encoder) throws
{
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.version, forKey: .version)
try container.encode(self.identifier, forKey: .identifier)
let json = self.anisetteData.json()
try container.encode(json, forKey: .anisetteData)
}
}
public struct PrepareAppRequest: ServerMessageProtocol
{
public var version = 1
public var identifier = "PrepareAppRequest"
public var udid: String
public var contentSize: Int
public var fileURL: URL?
public init(udid: String, contentSize: Int, fileURL: URL? = nil)
{
self.udid = udid
self.contentSize = contentSize
self.fileURL = fileURL
}
}
public struct BeginInstallationRequest: ServerMessageProtocol
{
public var version = 3
public var identifier = "BeginInstallationRequest"
// If activeProfiles is non-nil, then AltServer should remove all profiles except active ones.
public var activeProfiles: Set<String>?
public var bundleIdentifier: String?
public init(activeProfiles: Set<String>?, bundleIdentifier: String?)
{
self.activeProfiles = activeProfiles
self.bundleIdentifier = bundleIdentifier
print("BeginInstallationRequest `activeProfiles`: \(String(describing: activeProfiles))")
print("BeginInstallationRequest `bundleIdentifier`: \(String(describing: bundleIdentifier))")
}
}
public struct InstallationProgressResponse: ServerMessageProtocol
{
public var version = 1
public var identifier = "InstallationProgressResponse"
public var progress: Double
public init(progress: Double)
{
self.progress = progress
}
}
public struct InstallProvisioningProfilesRequest: ServerMessageProtocol
{
public var version = 1
public var identifier = "InstallProvisioningProfilesRequest"
public var udid: String
public var provisioningProfiles: Set<ALTProvisioningProfile>
// If activeProfiles is non-nil, then AltServer should remove all profiles except active ones.
public var activeProfiles: Set<String>?
private enum CodingKeys: String, CodingKey
{
case identifier
case version
case udid
case provisioningProfiles
case activeProfiles
}
public init(udid: String, provisioningProfiles: Set<ALTProvisioningProfile>, activeProfiles: Set<String>?)
{
self.udid = udid
self.provisioningProfiles = provisioningProfiles
self.activeProfiles = activeProfiles
print("InstallProvisioningProfilesRequest `self.udid`: \(self.udid)")
print("InstallProvisioningProfilesRequest `self.provisioningProfiles`: \(self.provisioningProfiles)")
print("InstallProvisioningProfilesRequest `self.activeProfiles`: \(String(describing: self.activeProfiles))")
}
public init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
self.version = try container.decode(Int.self, forKey: .version)
self.identifier = try container.decode(String.self, forKey: .identifier)
self.udid = try container.decode(String.self, forKey: .udid)
let rawProvisioningProfiles = try container.decode([Data].self, forKey: .provisioningProfiles)
let provisioningProfiles = try rawProvisioningProfiles.map { (data) -> ALTProvisioningProfile in
guard let profile = ALTProvisioningProfile(data: data) else {
throw DecodingError.dataCorruptedError(forKey: CodingKeys.provisioningProfiles, in: container, debugDescription: "Could not parse provisioning profile from data.")
}
return profile
}
self.provisioningProfiles = Set(provisioningProfiles)
self.activeProfiles = try container.decodeIfPresent(Set<String>.self, forKey: .activeProfiles)
}
public func encode(to encoder: Encoder) throws
{
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.version, forKey: .version)
try container.encode(self.identifier, forKey: .identifier)
try container.encode(self.udid, forKey: .udid)
try container.encode(self.provisioningProfiles.map { $0.data }, forKey: .provisioningProfiles)
try container.encodeIfPresent(self.activeProfiles, forKey: .activeProfiles)
}
}
public struct InstallProvisioningProfilesResponse: ServerMessageProtocol
{
public var version = 1
public var identifier = "InstallProvisioningProfilesResponse"
public init()
{
}
}
public struct RemoveProvisioningProfilesRequest: ServerMessageProtocol
{
public var version = 1
public var identifier = "RemoveProvisioningProfilesRequest"
public var udid: String
public var bundleIdentifiers: Set<String>
public init(udid: String, bundleIdentifiers: Set<String>)
{
self.udid = udid
self.bundleIdentifiers = bundleIdentifiers
}
}
public struct RemoveProvisioningProfilesResponse: ServerMessageProtocol
{
public var version = 1
public var identifier = "RemoveProvisioningProfilesResponse"
public init()
{
}
}
public struct RemoveAppRequest: ServerMessageProtocol
{
public var version = 1
public var identifier = "RemoveAppRequest"
public var udid: String
public var bundleIdentifier: String
public init(udid: String, bundleIdentifier: String)
{
self.udid = udid
self.bundleIdentifier = bundleIdentifier
}
}
public struct RemoveAppResponse: ServerMessageProtocol
{
public var version = 1
public var identifier = "RemoveAppResponse"
public init()
{
}
}
public struct EnableUnsignedCodeExecutionRequest: ServerMessageProtocol
{
public var version = 1
public var identifier = "EnableUnsignedCodeExecutionRequest"
public var udid: String
public var processID: Int?
public var processName: String?
public init(udid: String, processID: Int? = nil, processName: String? = nil)
{
self.udid = udid
self.processID = processID
self.processName = processName
}
}
public struct EnableUnsignedCodeExecutionResponse: ServerMessageProtocol
{
public var version = 1
public var identifier = "EnableUnsignedCodeExecutionResponse"
public init()
{
}
}