From e5e472d6407804c722609c4a455b174aff1faf16 Mon Sep 17 00:00:00 2001 From: DimitarTachev Date: Fri, 23 Aug 2019 09:01:42 +0300 Subject: [PATCH 1/2] fix: use the secure uninstall application (the old one is not working on wifi devices) --- IOSDeviceLib/Constants.h | 2 ++ IOSDeviceLib/Declarations.h | 4 ++-- IOSDeviceLib/IOSDeviceLib.cpp | 20 ++++++++++++++------ typings/interfaces.d.ts | 1 + 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/IOSDeviceLib/Constants.h b/IOSDeviceLib/Constants.h index d007060..dd8a71f 100644 --- a/IOSDeviceLib/Constants.h +++ b/IOSDeviceLib/Constants.h @@ -24,6 +24,7 @@ static const unsigned kCFStringEncodingUTF8 = 0x08000100; static const unsigned kAMDNotFoundError = 0xe8000008; static const unsigned kAMDAPIInternalError = 0xe8000067; static const int kUSBInterfaceType = 1; +static const int kWIFIInterfaceType = 2; static const unsigned kAppleServiceNotStartedErrorCode = 0xE8000063; static const unsigned kMountImageAlreadyMounted = 0xE8000076; // Note: This error code is actually named kAMDMobileImageMounterImageMountFailed but AppBuilder CLI and other sources think that getting this exit code during a mount is okay static const unsigned kIncompatibleSignature = 0xE8000033; // Note: This error code is actually named kAMDInvalidDiskImageError but CLI and other sources think that getting this exit code during a mount is okay @@ -69,6 +70,7 @@ static const char *kResponseCommandType = "responseCommandType"; static const char *kResponsePropertyName = "responsePropertyName"; static const char *kShouldWaitForResponse = "shouldWaitForResponse"; static const char *kCommandType = "commandType"; +static const char *kConnectionType = "connectionType"; static const char *kTimeout = "timeout"; static const char *kPort = "port"; static const char *kHost = "host"; diff --git a/IOSDeviceLib/Declarations.h b/IOSDeviceLib/Declarations.h index b6cf262..b33cdf9 100644 --- a/IOSDeviceLib/Declarations.h +++ b/IOSDeviceLib/Declarations.h @@ -168,7 +168,7 @@ typedef void(__cdecl *cfdictionary_get_keys_and_values)(CFDictionaryRef, const v typedef CFStringRef(__cdecl *cfstring_create_with_cstring)(void*, const char*, unsigned); typedef CFArrayRef(__cdecl *cfarray_create)(void*, const void**, long, void**); typedef unsigned(__cdecl *device_secure_operation_with_path)(int, const DeviceInfo*, CFURLRef, CFDictionaryRef, void(*f)(), int); -typedef unsigned(__cdecl *device_secure_operation_with_bundle_id)(int, const DeviceInfo*, CFStringRef, int, void(*f)(), int); +typedef unsigned(__cdecl *device_secure_operation_with_bundle_id)(ServiceConnRef connection, const DeviceInfo*, CFStringRef *bundleIdentifier, CFDictionaryRef *params, void (*installCallback)(CFDictionaryRef*, void *)); typedef void(__cdecl *cfrelease)(CFStringRef); typedef CFDictionaryRef(__cdecl *cfdictionary_create)(void *, void*, void*, int, void*, void*); @@ -276,8 +276,8 @@ extern "C" unsigned AMDeviceCreateHouseArrestService(const DeviceInfo*, CFStringRef identifier, void * unknown, AFCConnectionRef * handle); int AMDeviceGetConnectionID(const DeviceInfo*); int AMDeviceGetInterfaceType(const DeviceInfo*); + unsigned AMDeviceSecureUninstallApplication(ServiceConnRef connection, const DeviceInfo*, CFStringRef bundleIdentifier, CFDictionaryRef params, void (*installCallback)(CFDictionaryRef*, void *)); unsigned AMDeviceUninstallApplication(HANDLE, CFStringRef, void*, void(*f)(), void*); - unsigned AMDeviceSecureUninstallApplication(int, const DeviceInfo*, CFStringRef, int, void(*f)(), int); unsigned AMDeviceStartSession(const DeviceInfo*); unsigned AMDeviceStopSession(const DeviceInfo*); unsigned AMDeviceConnect(const DeviceInfo*); diff --git a/IOSDeviceLib/IOSDeviceLib.cpp b/IOSDeviceLib/IOSDeviceLib.cpp index 1c0db62..370ba68 100644 --- a/IOSDeviceLib/IOSDeviceLib.cpp +++ b/IOSDeviceLib/IOSDeviceLib.cpp @@ -134,6 +134,7 @@ int start_session(std::string& device_identifier) { const DeviceInfo* device_info = devices[device_identifier].device_info; UNLOCK_MUTEX_AND_RETURN_IF_FAILED_RESULT(AMDeviceConnect(device_info), start_session_mutex); + assert(AMDeviceIsPaired(device_info)); UNLOCK_MUTEX_AND_RETURN_IF_FAILED_RESULT(AMDeviceValidatePairing(device_info), start_session_mutex); UNLOCK_MUTEX_AND_RETURN_IF_FAILED_RESULT(AMDeviceStartSession(device_info), start_session_mutex); } @@ -242,6 +243,10 @@ void get_device_properties(std::string device_identifier, json &result) result["deviceName"] = get_device_property_value(device_identifier, "DeviceName"); result["productVersion"] = get_device_property_value(device_identifier, kProductVersion); result["deviceColor"] = get_device_property_value(device_identifier, "DeviceColor"); + // available values: + // "BluetoothAddress","BoardId","CPUArchitecture","ChipID","DeviceClass", + // "DeviceColor","DeviceName","FirmwareVersion","HardwareModel", + // "ModelNumber","ProductType","ProductVersion","UniqueDeviceID","WiFiAddress" } inline bool has_complete_status(std::map& dict) @@ -259,11 +264,12 @@ void on_device_found(const DevicePointer* device_ptr, std::string device_identif 2 - wifi interface type */ int interface_type = AMDeviceGetInterfaceType(device_ptr->device_info); - if (interface_type == kUSBInterfaceType) { + if (interface_type == kUSBInterfaceType || interface_type == kWIFIInterfaceType) { devices[device_identifier] = { device_ptr->device_info, nullptr }; result[kEventString] = eventString; + result[kConnectionType] = interface_type; get_device_properties(device_identifier, result); - } + } } void device_notification_callback(const DevicePointer* device_ptr) @@ -497,14 +503,16 @@ void uninstall_application(std::string application_identifier, std::string devic return; } - HANDLE socket = start_secure_service(device_identifier, kInstallationProxy, method_id, true, false).socket; - if (!socket) + ServiceInfo serviceInfo = start_secure_service(device_identifier, kInstallationProxy, method_id, true, false); + if (!serviceInfo.socket) { return; } CFStringRef appid_cfstring = create_CFString(application_identifier.c_str()); - unsigned result = AMDeviceUninstallApplication(socket, appid_cfstring, NULL, [] {}, NULL); + DeviceInfo* deviceInfo = devices[device_identifier].device_info; + CFDictionaryRef params = CFDictionaryCreate(NULL, {}, {}, 0, NULL, NULL); + unsigned result = AMDeviceSecureUninstallApplication(serviceInfo.connection, deviceInfo, appid_cfstring, params, NULL); CFRelease(appid_cfstring); if (result) @@ -1137,7 +1145,7 @@ void post_notification(std::string device_identifier, PostNotificationInfo post_ void await_notification_response(std::string device_identifier, AwaitNotificationResponseInfo await_notification_response_info, std::string method_id) { ServiceConnRef connection = serviceConnections[(int)await_notification_response_info.socket]; - std::string invalid_connection_error_message = "Invalid connectionId: " + std::to_string(await_notification_response_info.socket); + std::string invalid_connection_error_message = "Invalid socket: " + std::to_string(await_notification_response_info.socket); PRINT_ERROR_AND_RETURN_IF_FAILED_RESULT(connection == nullptr, invalid_connection_error_message.c_str(), device_identifier, method_id); ServiceInfo currentNotificationProxy = devices[device_identifier].services[kNotificationProxy]; diff --git a/typings/interfaces.d.ts b/typings/interfaces.d.ts index 324581b..8db4508 100644 --- a/typings/interfaces.d.ts +++ b/typings/interfaces.d.ts @@ -10,6 +10,7 @@ declare global { productType?: string; productVersion?: string; status?: string; + connectionType: number; } interface IDeviceId { From 136f1de47ba9d01783cb4e12a7fb0ac3f37ab94a Mon Sep 17 00:00:00 2001 From: DimitarTachev Date: Fri, 23 Aug 2019 14:59:41 +0300 Subject: [PATCH 2/2] fix: introduce a deviceUpdated event in order to support devices with multiple connection types --- IOSDeviceLib/Constants.h | 4 +- IOSDeviceLib/Declarations.h | 6 ++- IOSDeviceLib/IOSDeviceLib.cpp | 78 +++++++++++++++++++++++---------- README.md | 2 + constants.js | 2 + ios-device-lib-stdio-handler.js | 3 ++ ios-device-lib.js | 3 +- package.json | 4 +- typings/interfaces.d.ts | 5 ++- 9 files changed, 76 insertions(+), 31 deletions(-) diff --git a/IOSDeviceLib/Constants.h b/IOSDeviceLib/Constants.h index dd8a71f..dbcd1bf 100644 --- a/IOSDeviceLib/Constants.h +++ b/IOSDeviceLib/Constants.h @@ -40,6 +40,7 @@ static const char *kUnreachableStatus = "Unreachable"; static const char *kConnectedStatus = "Connected"; static const char *kDeviceFound = "deviceFound"; +static const char *kDeviceUpdated = "deviceUpdated"; static const char *kDeviceLost = "deviceLost"; static const char *kDeviceTrusted = "deviceTrusted"; static const char *kDeviceUnknown = "deviceUnknown"; @@ -70,7 +71,8 @@ static const char *kResponseCommandType = "responseCommandType"; static const char *kResponsePropertyName = "responsePropertyName"; static const char *kShouldWaitForResponse = "shouldWaitForResponse"; static const char *kCommandType = "commandType"; -static const char *kConnectionType = "connectionType"; +static const char *kIsWiFiConnected = "isWiFiConnected"; +static const char *kIsUSBConnected = "isUSBConnected"; static const char *kTimeout = "timeout"; static const char *kPort = "port"; static const char *kHost = "host"; diff --git a/IOSDeviceLib/Declarations.h b/IOSDeviceLib/Declarations.h index b33cdf9..0c9a851 100644 --- a/IOSDeviceLib/Declarations.h +++ b/IOSDeviceLib/Declarations.h @@ -113,6 +113,8 @@ struct DeviceData { std::map services; int sessions; std::map apps_cache; + int isWiFiConnected; + int isUSBConnected; void kill_device_server() { @@ -168,7 +170,7 @@ typedef void(__cdecl *cfdictionary_get_keys_and_values)(CFDictionaryRef, const v typedef CFStringRef(__cdecl *cfstring_create_with_cstring)(void*, const char*, unsigned); typedef CFArrayRef(__cdecl *cfarray_create)(void*, const void**, long, void**); typedef unsigned(__cdecl *device_secure_operation_with_path)(int, const DeviceInfo*, CFURLRef, CFDictionaryRef, void(*f)(), int); -typedef unsigned(__cdecl *device_secure_operation_with_bundle_id)(ServiceConnRef connection, const DeviceInfo*, CFStringRef *bundleIdentifier, CFDictionaryRef *params, void (*installCallback)(CFDictionaryRef*, void *)); +typedef unsigned(__cdecl *device_secure_operation_with_bundle_id)(ServiceConnRef connection, const DeviceInfo*, CFStringRef bundleIdentifier, CFDictionaryRef params, void (*installCallback)(CFDictionaryRef*, void *)); typedef void(__cdecl *cfrelease)(CFStringRef); typedef CFDictionaryRef(__cdecl *cfdictionary_create)(void *, void*, void*, int, void*, void*); @@ -276,7 +278,7 @@ extern "C" unsigned AMDeviceCreateHouseArrestService(const DeviceInfo*, CFStringRef identifier, void * unknown, AFCConnectionRef * handle); int AMDeviceGetConnectionID(const DeviceInfo*); int AMDeviceGetInterfaceType(const DeviceInfo*); - unsigned AMDeviceSecureUninstallApplication(ServiceConnRef connection, const DeviceInfo*, CFStringRef bundleIdentifier, CFDictionaryRef params, void (*installCallback)(CFDictionaryRef*, void *)); + unsigned AMDeviceSecureUninstallApplication(ServiceConnRef connection, const DeviceInfo*, CFStringRef bundleIdentifier, CFDictionaryRef params, void (*installCallback)(CFDictionaryRef*, void *)); unsigned AMDeviceUninstallApplication(HANDLE, CFStringRef, void*, void(*f)(), void*); unsigned AMDeviceStartSession(const DeviceInfo*); unsigned AMDeviceStopSession(const DeviceInfo*); diff --git a/IOSDeviceLib/IOSDeviceLib.cpp b/IOSDeviceLib/IOSDeviceLib.cpp index 370ba68..65927bd 100644 --- a/IOSDeviceLib/IOSDeviceLib.cpp +++ b/IOSDeviceLib/IOSDeviceLib.cpp @@ -134,7 +134,7 @@ int start_session(std::string& device_identifier) { const DeviceInfo* device_info = devices[device_identifier].device_info; UNLOCK_MUTEX_AND_RETURN_IF_FAILED_RESULT(AMDeviceConnect(device_info), start_session_mutex); - assert(AMDeviceIsPaired(device_info)); + assert(AMDeviceIsPaired(device_info)); UNLOCK_MUTEX_AND_RETURN_IF_FAILED_RESULT(AMDeviceValidatePairing(device_info), start_session_mutex); UNLOCK_MUTEX_AND_RETURN_IF_FAILED_RESULT(AMDeviceStartSession(device_info), start_session_mutex); } @@ -243,10 +243,10 @@ void get_device_properties(std::string device_identifier, json &result) result["deviceName"] = get_device_property_value(device_identifier, "DeviceName"); result["productVersion"] = get_device_property_value(device_identifier, kProductVersion); result["deviceColor"] = get_device_property_value(device_identifier, "DeviceColor"); - // available values: - // "BluetoothAddress","BoardId","CPUArchitecture","ChipID","DeviceClass", - // "DeviceColor","DeviceName","FirmwareVersion","HardwareModel", - // "ModelNumber","ProductType","ProductVersion","UniqueDeviceID","WiFiAddress" + // available values: + // "BluetoothAddress","BoardId","CPUArchitecture","ChipID","DeviceClass", + // "DeviceColor","DeviceName","FirmwareVersion","HardwareModel", + // "ModelNumber","ProductType","ProductVersion","UniqueDeviceID","WiFiAddress" } inline bool has_complete_status(std::map& dict) @@ -254,7 +254,15 @@ inline bool has_complete_status(std::map& dict) return boost::any_cast(dict[kStatusKey]) == kComplete; } -void on_device_found(const DevicePointer* device_ptr, std::string device_identifier, std::string eventString, json &result) + +void update_device_result(std::string device_identifier, json &result) +{ + result[kIsUSBConnected] = devices[device_identifier].isUSBConnected; + result[kIsWiFiConnected] = devices[device_identifier].isWiFiConnected; + get_device_properties(device_identifier, result); +} + +void on_device_found(const DevicePointer* device_ptr, std::string device_identifier, json &result) { /* Interface type can be one of the followings: @@ -265,11 +273,23 @@ void on_device_found(const DevicePointer* device_ptr, std::string device_identif */ int interface_type = AMDeviceGetInterfaceType(device_ptr->device_info); if (interface_type == kUSBInterfaceType || interface_type == kWIFIInterfaceType) { - devices[device_identifier] = { device_ptr->device_info, nullptr }; - result[kEventString] = eventString; - result[kConnectionType] = interface_type; - get_device_properties(device_identifier, result); - } + if (devices.count(device_identifier)) { + devices[device_identifier].device_info = device_ptr->device_info; + result[kEventString] = kDeviceUpdated; + } else { + devices[device_identifier] = { device_ptr->device_info, nullptr }; + result[kEventString] = kDeviceFound; + } + + + if (interface_type == kUSBInterfaceType) { + devices[device_identifier].isUSBConnected = 1; + } else { + devices[device_identifier].isWiFiConnected = 1; + } + + update_device_result(device_identifier, result); + } } void device_notification_callback(const DevicePointer* device_ptr) @@ -281,21 +301,33 @@ void device_notification_callback(const DevicePointer* device_ptr) { case kADNCIMessageConnected: { - on_device_found(device_ptr, device_identifier, kDeviceFound, result); + on_device_found(device_ptr, device_identifier, result); break; } case kADNCIMessageDisconnected: { - if (devices.count(device_identifier)) - { - if (devices[device_identifier].apps_cache.size()) - { - cleanup_file_resources(device_identifier); + if (devices.count(device_identifier)) { + int interface_type = AMDeviceGetInterfaceType(device_ptr->device_info); + if (interface_type == kUSBInterfaceType) { + devices[device_identifier].isUSBConnected = 0; + } else if (interface_type == kWIFIInterfaceType) { + devices[device_identifier].isWiFiConnected = 0; } + + if (!devices[device_identifier].isUSBConnected && !devices[device_identifier].isWiFiConnected) { + if (devices[device_identifier].apps_cache.size()) + { + cleanup_file_resources(device_identifier); + } - devices.erase(device_identifier); + devices.erase(device_identifier); + result[kEventString] = kDeviceLost; + } else { + result[kEventString] = kDeviceUpdated; + update_device_result(device_identifier, result); + } } - result[kEventString] = kDeviceLost; + break; } case kADNCIMessageUnknown: @@ -305,7 +337,7 @@ void device_notification_callback(const DevicePointer* device_ptr) } case kADNCIMessageTrusted: { - on_device_found(device_ptr, device_identifier, kDeviceTrusted, result); + on_device_found(device_ptr, device_identifier, result); break; } } @@ -510,9 +542,9 @@ void uninstall_application(std::string application_identifier, std::string devic } CFStringRef appid_cfstring = create_CFString(application_identifier.c_str()); - DeviceInfo* deviceInfo = devices[device_identifier].device_info; - CFDictionaryRef params = CFDictionaryCreate(NULL, {}, {}, 0, NULL, NULL); - unsigned result = AMDeviceSecureUninstallApplication(serviceInfo.connection, deviceInfo, appid_cfstring, params, NULL); + DeviceInfo* deviceInfo = devices[device_identifier].device_info; + CFDictionaryRef params = CFDictionaryCreate(NULL, {}, {}, 0, NULL, NULL); + unsigned result = AMDeviceSecureUninstallApplication(serviceInfo.connection, deviceInfo, appid_cfstring, params, NULL); CFRelease(appid_cfstring); if (result) diff --git a/README.md b/README.md index 843a6c2..c882584 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ const dl = new DeviceLib.IOSDeviceLib(device => { console.log("An error occurred ;(", err); }); }); +}, device => { + console.log("Device UPDATED!", device); }, device => { console.log("Device LOST!", device); }); diff --git a/constants.js b/constants.js index 3d97a9a..41b1761 100644 --- a/constants.js +++ b/constants.js @@ -2,10 +2,12 @@ exports.DataEventName = "data"; exports.DeviceFoundEventName = "deviceFound"; +exports.DeviceUpdatedEventName = "deviceUpdated"; exports.DeviceLostEventName = "deviceLost"; exports.DeviceEventEnum = { kDeviceFound: "deviceFound", + kDeviceUpdated: "deviceUpdated", kDeviceLost: "deviceLost", kDeviceTrusted: "deviceTrusted", kDeviceUnknown: "deviceUnknown" diff --git a/ios-device-lib-stdio-handler.js b/ios-device-lib-stdio-handler.js index f528a78..cf4677b 100644 --- a/ios-device-lib-stdio-handler.js +++ b/ios-device-lib-stdio-handler.js @@ -48,6 +48,9 @@ class IOSDeviceLibStdioHandler extends EventEmitter { case Constants.DeviceEventEnum.kDeviceFound: this.emit(Constants.DeviceFoundEventName, message); break; + case Constants.DeviceEventEnum.kDeviceUpdated: + this.emit(Constants.DeviceUpdatedEventName, message); + break; case Constants.DeviceEventEnum.kDeviceLost: this.emit(Constants.DeviceLostEventName, message); break; diff --git a/ios-device-lib.js b/ios-device-lib.js index c80d202..93fa5ee 100644 --- a/ios-device-lib.js +++ b/ios-device-lib.js @@ -27,12 +27,13 @@ const Events = { }; class IOSDeviceLib extends EventEmitter { - constructor(onDeviceFound, onDeviceLost, options) { + constructor(onDeviceFound, onDeviceUpdated, onDeviceLost, options) { super(); this._options = options || {}; this._iosDeviceLibStdioHandler = new IOSDeviceLibStdioHandler(this._options); this._iosDeviceLibStdioHandler.startReadingData(); this._iosDeviceLibStdioHandler.on(Constants.DeviceFoundEventName, onDeviceFound); + this._iosDeviceLibStdioHandler.on(Constants.DeviceUpdatedEventName, onDeviceUpdated); this._iosDeviceLibStdioHandler.on(Constants.DeviceLostEventName, onDeviceLost); } diff --git a/package.json b/package.json index 831173e..21995bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ios-device-lib", - "version": "0.6.0", + "version": "0.7.0", "description": "", "types": "./typings/ios-device-lib.d.ts", "main": "index.js", @@ -28,4 +28,4 @@ "istanbul": "0.4.5", "mocha": "5.2.0" } -} +} \ No newline at end of file diff --git a/typings/interfaces.d.ts b/typings/interfaces.d.ts index 8db4508..4113d59 100644 --- a/typings/interfaces.d.ts +++ b/typings/interfaces.d.ts @@ -10,7 +10,8 @@ declare global { productType?: string; productVersion?: string; status?: string; - connectionType: number; + isUSBConnected: number; + isWiFiConnected: number; } interface IDeviceId { @@ -133,7 +134,7 @@ declare global { } interface IOSDeviceLib extends NodeJS.EventEmitter { - new(onDeviceFound: (found: IDeviceActionInfo) => void, onDeviceLost: (found: IDeviceActionInfo) => void): IOSDeviceLib; + new(onDeviceFound: (found: IDeviceActionInfo) => void, onDeviceUpdated: (updated: IDeviceActionInfo) => void, onDeviceLost: (found: IDeviceActionInfo) => void): IOSDeviceLib; install(ipaPath: string, deviceIdentifiers: string[]): Promise[]; uninstall(ipaPath: string, deviceIdentifiers: string[]): Promise[]; list(listArray: IReadOperationData[]): Promise[];