pymobiledevice3 5.0.1__py3-none-any.whl → 5.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pymobiledevice3 might be problematic. Click here for more details.

Files changed (143) hide show
  1. misc/plist_sniffer.py +15 -15
  2. misc/remotexpc_sniffer.py +29 -28
  3. pymobiledevice3/__main__.py +128 -102
  4. pymobiledevice3/_version.py +2 -2
  5. pymobiledevice3/bonjour.py +36 -59
  6. pymobiledevice3/ca.py +32 -24
  7. pymobiledevice3/cli/activation.py +7 -7
  8. pymobiledevice3/cli/afc.py +19 -19
  9. pymobiledevice3/cli/amfi.py +4 -4
  10. pymobiledevice3/cli/apps.py +51 -39
  11. pymobiledevice3/cli/backup.py +58 -32
  12. pymobiledevice3/cli/bonjour.py +25 -18
  13. pymobiledevice3/cli/cli_common.py +112 -81
  14. pymobiledevice3/cli/companion_proxy.py +4 -4
  15. pymobiledevice3/cli/completions.py +10 -10
  16. pymobiledevice3/cli/crash.py +37 -31
  17. pymobiledevice3/cli/developer.py +602 -520
  18. pymobiledevice3/cli/diagnostics.py +38 -33
  19. pymobiledevice3/cli/lockdown.py +79 -74
  20. pymobiledevice3/cli/mounter.py +85 -68
  21. pymobiledevice3/cli/notification.py +10 -10
  22. pymobiledevice3/cli/pcap.py +19 -14
  23. pymobiledevice3/cli/power_assertion.py +12 -10
  24. pymobiledevice3/cli/processes.py +10 -10
  25. pymobiledevice3/cli/profile.py +88 -77
  26. pymobiledevice3/cli/provision.py +17 -17
  27. pymobiledevice3/cli/remote.py +186 -110
  28. pymobiledevice3/cli/restore.py +43 -40
  29. pymobiledevice3/cli/springboard.py +30 -28
  30. pymobiledevice3/cli/syslog.py +85 -58
  31. pymobiledevice3/cli/usbmux.py +21 -20
  32. pymobiledevice3/cli/version.py +3 -2
  33. pymobiledevice3/cli/webinspector.py +157 -79
  34. pymobiledevice3/common.py +1 -1
  35. pymobiledevice3/exceptions.py +154 -60
  36. pymobiledevice3/irecv.py +49 -53
  37. pymobiledevice3/irecv_devices.py +1489 -492
  38. pymobiledevice3/lockdown.py +396 -242
  39. pymobiledevice3/lockdown_service_provider.py +5 -7
  40. pymobiledevice3/osu/os_utils.py +18 -9
  41. pymobiledevice3/osu/posix_util.py +28 -15
  42. pymobiledevice3/osu/win_util.py +14 -8
  43. pymobiledevice3/pair_records.py +19 -19
  44. pymobiledevice3/remote/common.py +4 -4
  45. pymobiledevice3/remote/core_device/app_service.py +94 -67
  46. pymobiledevice3/remote/core_device/core_device_service.py +17 -14
  47. pymobiledevice3/remote/core_device/device_info.py +5 -5
  48. pymobiledevice3/remote/core_device/diagnostics_service.py +10 -8
  49. pymobiledevice3/remote/core_device/file_service.py +47 -33
  50. pymobiledevice3/remote/remote_service_discovery.py +53 -35
  51. pymobiledevice3/remote/remotexpc.py +64 -42
  52. pymobiledevice3/remote/tunnel_service.py +371 -293
  53. pymobiledevice3/remote/utils.py +12 -11
  54. pymobiledevice3/remote/xpc_message.py +145 -125
  55. pymobiledevice3/resources/dsc_uuid_map.py +19 -19
  56. pymobiledevice3/resources/firmware_notifications.py +16 -16
  57. pymobiledevice3/restore/asr.py +27 -27
  58. pymobiledevice3/restore/base_restore.py +90 -47
  59. pymobiledevice3/restore/consts.py +87 -66
  60. pymobiledevice3/restore/device.py +11 -11
  61. pymobiledevice3/restore/fdr.py +46 -46
  62. pymobiledevice3/restore/ftab.py +19 -19
  63. pymobiledevice3/restore/img4.py +130 -133
  64. pymobiledevice3/restore/mbn.py +35 -54
  65. pymobiledevice3/restore/recovery.py +125 -135
  66. pymobiledevice3/restore/restore.py +524 -523
  67. pymobiledevice3/restore/restore_options.py +122 -115
  68. pymobiledevice3/restore/restored_client.py +25 -22
  69. pymobiledevice3/restore/tss.py +378 -270
  70. pymobiledevice3/service_connection.py +50 -46
  71. pymobiledevice3/services/accessibilityaudit.py +137 -127
  72. pymobiledevice3/services/afc.py +350 -291
  73. pymobiledevice3/services/amfi.py +21 -18
  74. pymobiledevice3/services/companion.py +23 -19
  75. pymobiledevice3/services/crash_reports.py +60 -46
  76. pymobiledevice3/services/debugserver_applist.py +3 -3
  77. pymobiledevice3/services/device_arbitration.py +8 -8
  78. pymobiledevice3/services/device_link.py +56 -48
  79. pymobiledevice3/services/diagnostics.py +971 -968
  80. pymobiledevice3/services/dtfetchsymbols.py +8 -8
  81. pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
  82. pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
  83. pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
  84. pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
  85. pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
  86. pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +442 -421
  87. pymobiledevice3/services/dvt/instruments/device_info.py +11 -11
  88. pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
  89. pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
  90. pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
  91. pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
  92. pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
  93. pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
  94. pymobiledevice3/services/dvt/instruments/process_control.py +25 -10
  95. pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
  96. pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
  97. pymobiledevice3/services/dvt/testmanaged/xcuitest.py +42 -52
  98. pymobiledevice3/services/file_relay.py +10 -10
  99. pymobiledevice3/services/heartbeat.py +8 -7
  100. pymobiledevice3/services/house_arrest.py +12 -15
  101. pymobiledevice3/services/installation_proxy.py +119 -100
  102. pymobiledevice3/services/lockdown_service.py +12 -5
  103. pymobiledevice3/services/misagent.py +22 -19
  104. pymobiledevice3/services/mobile_activation.py +84 -72
  105. pymobiledevice3/services/mobile_config.py +330 -301
  106. pymobiledevice3/services/mobile_image_mounter.py +137 -116
  107. pymobiledevice3/services/mobilebackup2.py +188 -150
  108. pymobiledevice3/services/notification_proxy.py +11 -11
  109. pymobiledevice3/services/os_trace.py +69 -51
  110. pymobiledevice3/services/pcapd.py +306 -306
  111. pymobiledevice3/services/power_assertion.py +10 -9
  112. pymobiledevice3/services/preboard.py +4 -4
  113. pymobiledevice3/services/remote_fetch_symbols.py +16 -14
  114. pymobiledevice3/services/remote_server.py +176 -146
  115. pymobiledevice3/services/restore_service.py +16 -16
  116. pymobiledevice3/services/screenshot.py +13 -10
  117. pymobiledevice3/services/simulate_location.py +7 -7
  118. pymobiledevice3/services/springboard.py +15 -15
  119. pymobiledevice3/services/syslog.py +5 -5
  120. pymobiledevice3/services/web_protocol/alert.py +3 -3
  121. pymobiledevice3/services/web_protocol/automation_session.py +183 -179
  122. pymobiledevice3/services/web_protocol/cdp_screencast.py +44 -36
  123. pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
  124. pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
  125. pymobiledevice3/services/web_protocol/driver.py +47 -45
  126. pymobiledevice3/services/web_protocol/element.py +74 -63
  127. pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
  128. pymobiledevice3/services/web_protocol/selenium_api.py +3 -3
  129. pymobiledevice3/services/web_protocol/session_protocol.py +15 -10
  130. pymobiledevice3/services/web_protocol/switch_to.py +11 -12
  131. pymobiledevice3/services/webinspector.py +129 -117
  132. pymobiledevice3/tcp_forwarder.py +35 -22
  133. pymobiledevice3/tunneld/api.py +20 -15
  134. pymobiledevice3/tunneld/server.py +212 -133
  135. pymobiledevice3/usbmux.py +183 -138
  136. pymobiledevice3/utils.py +14 -11
  137. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/METADATA +1 -1
  138. pymobiledevice3-5.0.3.dist-info/RECORD +173 -0
  139. pymobiledevice3-5.0.1.dist-info/RECORD +0 -173
  140. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/WHEEL +0 -0
  141. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/entry_points.txt +0 -0
  142. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/licenses/LICENSE +0 -0
  143. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/top_level.txt +0 -0
@@ -17,8 +17,12 @@ from tqdm import tqdm, trange
17
17
 
18
18
  from pymobiledevice3.exceptions import ConnectionFailedError, NoDeviceConnectedError, PyMobileDevice3Exception
19
19
  from pymobiledevice3.restore.asr import DEFAULT_ASR_SYNC_PORT, ASRClient
20
- from pymobiledevice3.restore.base_restore import RESTORE_VARIANT_ERASE_INSTALL, RESTORE_VARIANT_MACOS_RECOVERY_OS, \
21
- RESTORE_VARIANT_UPGRADE_INSTALL, BaseRestore
20
+ from pymobiledevice3.restore.base_restore import (
21
+ RESTORE_VARIANT_ERASE_INSTALL,
22
+ RESTORE_VARIANT_MACOS_RECOVERY_OS,
23
+ RESTORE_VARIANT_UPGRADE_INSTALL,
24
+ BaseRestore,
25
+ )
22
26
  from pymobiledevice3.restore.consts import PROGRESS_BAR_OPERATIONS, lpol_file
23
27
  from pymobiledevice3.restore.device import Device
24
28
  from pymobiledevice3.restore.fdr import FDRClient, fdr_type, start_fdr_thread
@@ -32,20 +36,21 @@ from pymobiledevice3.service_connection import ServiceConnection
32
36
  from pymobiledevice3.utils import asyncio_print_traceback, plist_access_path
33
37
 
34
38
  known_errors = {
35
- 0xFFFFFFFFFFFFFFFF: 'verification error',
36
- 6: 'disk failure',
37
- 14: 'fail',
38
- 27: 'failed to mount filesystems',
39
- 50: 'failed to load SEP firmware',
40
- 51: 'failed to load SEP firmware',
41
- 53: 'failed to recover FDR data',
42
- 1015: 'X-Gold Baseband Update Failed. Defective Unit?',
39
+ 0xFFFFFFFFFFFFFFFF: "verification error",
40
+ 6: "disk failure",
41
+ 14: "fail",
42
+ 27: "failed to mount filesystems",
43
+ 50: "failed to load SEP firmware",
44
+ 51: "failed to load SEP firmware",
45
+ 53: "failed to recover FDR data",
46
+ 1015: "X-Gold Baseband Update Failed. Defective Unit?",
43
47
  }
44
48
 
45
49
 
46
50
  class Restore(BaseRestore):
47
- def __init__(self, ipsw: zipfile.ZipFile, device: Device, tss=None, behavior: Behavior = Behavior.Update,
48
- ignore_fdr=False):
51
+ def __init__(
52
+ self, ipsw: zipfile.ZipFile, device: Device, tss=None, behavior: Behavior = Behavior.Update, ignore_fdr=False
53
+ ):
49
54
  super().__init__(ipsw, device, tss, behavior)
50
55
  self.recovery = Recovery(ipsw, device, tss=tss, behavior=behavior)
51
56
  self.bbtss: Optional[TSSResponse] = None
@@ -74,85 +79,72 @@ class Restore(BaseRestore):
74
79
  # data request messages are sent by restored whenever it requires
75
80
  # files sent to the server by the client. these data requests include
76
81
  # SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests
77
- 'DataRequestMsg': self.handle_data_request_msg,
78
- 'AsyncDataRequestMsg': self.handle_async_data_request_msg,
79
-
82
+ "DataRequestMsg": self.handle_data_request_msg,
83
+ "AsyncDataRequestMsg": self.handle_async_data_request_msg,
80
84
  # restore logs are available if a previous restore failed
81
- 'PreviousRestoreLogMsg': self.handle_previous_restore_log_msg,
82
-
85
+ "PreviousRestoreLogMsg": self.handle_previous_restore_log_msg,
83
86
  # progress notification messages sent by the restored inform the client
84
87
  # of it's current operation and sometimes percent of progress is complete
85
- 'ProgressMsg': self.handle_progress_msg,
86
-
88
+ "ProgressMsg": self.handle_progress_msg,
87
89
  # status messages usually indicate the current state of the restored
88
90
  # process or often to signal an error has been encountered
89
- 'StatusMsg': self.handle_status_msg,
90
-
91
+ "StatusMsg": self.handle_status_msg,
91
92
  # checkpoint notifications
92
- 'CheckpointMsg': self.handle_checkpoint_msg,
93
-
93
+ "CheckpointMsg": self.handle_checkpoint_msg,
94
94
  # baseband update message
95
- 'BBUpdateStatusMsg': self.handle_bb_update_status_msg,
96
-
95
+ "BBUpdateStatusMsg": self.handle_bb_update_status_msg,
97
96
  # baseband updater output data request
98
- 'BasebandUpdaterOutputData': self.handle_baseband_updater_output_data,
99
-
97
+ "BasebandUpdaterOutputData": self.handle_baseband_updater_output_data,
100
98
  # report backtrace from restored crash
101
- 'RestoredCrash': self.handle_restored_crash,
102
-
99
+ "RestoredCrash": self.handle_restored_crash,
103
100
  # report new async contexts
104
- 'AsyncWait': self.handle_async_wait,
105
-
101
+ "AsyncWait": self.handle_async_wait,
106
102
  # handle attestation
107
- 'RestoreAttestation': self.handle_restore_attestation,
103
+ "RestoreAttestation": self.handle_restore_attestation,
108
104
  }
109
105
 
110
106
  self._data_request_handlers = {
111
107
  # this request is sent when restored is ready to receive the filesystem
112
- 'SystemImageData': self.send_filesystem,
113
-
114
- 'BuildIdentityDict': self.send_buildidentity,
115
- 'PersonalizedBootObjectV3': self.send_personalized_boot_object_v3,
116
- 'SourceBootObjectV4': self.send_source_boot_object_v4,
117
- 'RecoveryOSLocalPolicy': self.send_restore_local_policy,
118
-
108
+ "SystemImageData": self.send_filesystem,
109
+ "BuildIdentityDict": self.send_buildidentity,
110
+ "PersonalizedBootObjectV3": self.send_personalized_boot_object_v3,
111
+ "SourceBootObjectV4": self.send_source_boot_object_v4,
112
+ "RecoveryOSLocalPolicy": self.send_restore_local_policy,
119
113
  # this request is sent when restored is ready to receive the filesystem
120
- 'RecoveryOSASRImage': self.send_filesystem,
121
-
114
+ "RecoveryOSASRImage": self.send_filesystem,
122
115
  # Send RecoveryOS RTD
123
- 'RecoveryOSRootTicketData': self.send_recovery_os_root_ticket,
124
-
116
+ "RecoveryOSRootTicketData": self.send_recovery_os_root_ticket,
125
117
  # send RootTicket (== APTicket from the TSS request)
126
- 'RootTicket': self.send_root_ticket,
127
-
128
- 'NORData': self.send_nor,
129
- 'BasebandData': self.send_baseband_data,
130
- 'FDRTrustData': self.send_fdr_trust_data,
131
- 'FirmwareUpdaterData': self.send_firmware_updater_data,
132
-
118
+ "RootTicket": self.send_root_ticket,
119
+ "NORData": self.send_nor,
120
+ "BasebandData": self.send_baseband_data,
121
+ "FDRTrustData": self.send_fdr_trust_data,
122
+ "FirmwareUpdaterData": self.send_firmware_updater_data,
133
123
  # TODO: verify
134
- 'FirmwareUpdaterPreflight': self.send_firmware_updater_preflight,
135
-
124
+ "FirmwareUpdaterPreflight": self.send_firmware_updater_preflight,
136
125
  # Added on iOS 18.0 beta1
137
- 'URLAsset': self.send_url_asset,
138
- 'StreamedImageDecryptionKey': self.send_streamed_image_decryption_key,
126
+ "URLAsset": self.send_url_asset,
127
+ "StreamedImageDecryptionKey": self.send_streamed_image_decryption_key,
139
128
  }
140
129
 
141
130
  self._data_request_components = {
142
- 'KernelCache': self.send_component,
143
- 'DeviceTree': self.send_component,
131
+ "KernelCache": self.send_component,
132
+ "DeviceTree": self.send_component,
144
133
  }
145
134
 
146
135
  def handle_async_data_request_msg(self, message: dict) -> typing.Coroutine:
147
- self._tasks.append(asyncio.create_task(self.handle_data_request_msg(message),
148
- name=f'AsyncDataRequestMsg-{message["DataType"]}'))
136
+ self._tasks.append(
137
+ asyncio.create_task(
138
+ self.handle_data_request_msg(message), name=f"AsyncDataRequestMsg-{message['DataType']}"
139
+ )
140
+ )
149
141
  return asyncio.sleep(0)
150
142
 
151
143
  async def send_filesystem(self, message: dict) -> None:
152
- self.logger.info('about to send filesystem...')
144
+ self.logger.info("about to send filesystem...")
153
145
 
154
- asr_port = message.get('DataPort', DEFAULT_ASR_SYNC_PORT)
155
- self.logger.info(f'connecting to ASR on port {asr_port}')
146
+ asr_port = message.get("DataPort", DEFAULT_ASR_SYNC_PORT)
147
+ self.logger.info(f"connecting to ASR on port {asr_port}")
156
148
  asr = ASRClient(self._restored.udid)
157
149
  while True:
158
150
  try:
@@ -161,46 +153,46 @@ class Restore(BaseRestore):
161
153
  except ConnectionFailedError:
162
154
  pass
163
155
 
164
- self.logger.info('connected to ASR')
156
+ self.logger.info("connected to ASR")
165
157
 
166
158
  # this step sends requested chunks of data from various offsets to asr, so
167
159
  # it can validate the filesystem before installing it
168
- self.logger.info('validating the filesystem')
160
+ self.logger.info("validating the filesystem")
169
161
 
170
- with self.ipsw.open_path(self.build_identity.get_component_path('OS')) as filesystem:
162
+ with self.ipsw.open_path(self.build_identity.get_component_path("OS")) as filesystem:
171
163
  await asr.perform_validation(filesystem)
172
- self.logger.info('filesystem validated')
164
+ self.logger.info("filesystem validated")
173
165
 
174
166
  # once the target filesystem has been validated, ASR then requests the
175
167
  # entire filesystem to be sent.
176
- self.logger.info('sending filesystem now...')
168
+ self.logger.info("sending filesystem now...")
177
169
  await asr.send_payload(filesystem)
178
170
 
179
171
  await asr.close()
180
172
 
181
173
  def get_build_identity_from_request(self, msg):
182
- return self.get_build_identity(msg['Arguments'].get('IsRecoveryOS', False))
174
+ return self.get_build_identity(msg["Arguments"].get("IsRecoveryOS", False))
183
175
 
184
176
  async def send_buildidentity(self, message: dict) -> None:
185
- self.logger.info('About to send BuildIdentity Dict...')
177
+ self.logger.info("About to send BuildIdentity Dict...")
186
178
  service = await self._get_service_for_data_request(message)
187
- req = {'BuildIdentityDict': dict(self.get_build_identity_from_request(message))}
188
- arguments = message['Arguments']
189
- variant = arguments.get('Variant', 'Erase')
190
- req['Variant'] = variant
191
- self.logger.info('Sending BuildIdentityDict now...')
179
+ req = {"BuildIdentityDict": dict(self.get_build_identity_from_request(message))}
180
+ arguments = message["Arguments"]
181
+ variant = arguments.get("Variant", "Erase")
182
+ req["Variant"] = variant
183
+ self.logger.info("Sending BuildIdentityDict now...")
192
184
  await service.aio_send_plist(req)
193
185
 
194
186
  async def extract_global_manifest(self) -> dict:
195
- build_info = self.build_identity.get('Info')
187
+ build_info = self.build_identity.get("Info")
196
188
  if build_info is None:
197
189
  raise PyMobileDevice3Exception('build identity does not contain an "Info" element')
198
190
 
199
- device_class = build_info.get('DeviceClass')
191
+ device_class = build_info.get("DeviceClass")
200
192
  if device_class is None:
201
193
  raise PyMobileDevice3Exception('build identity does not contain an "DeviceClass" element')
202
194
 
203
- macos_variant = build_info.get('MacOSVariant')
195
+ macos_variant = build_info.get("MacOSVariant")
204
196
  if macos_variant is None:
205
197
  raise PyMobileDevice3Exception('build identity does not contain an "MacOSVariant" element')
206
198
 
@@ -208,67 +200,68 @@ class Restore(BaseRestore):
208
200
  return self.ipsw.get_global_manifest(macos_variant, device_class)
209
201
 
210
202
  async def send_personalized_boot_object_v3(self, message: dict) -> None:
211
- self.logger.debug('send_personalized_boot_object_v3')
203
+ self.logger.debug("send_personalized_boot_object_v3")
212
204
  service = await self._get_service_for_data_request(message)
213
- image_name = message['Arguments']['ImageName']
205
+ image_name = message["Arguments"]["ImageName"]
214
206
  component_name = image_name
215
- self.logger.info(f'About to send {component_name}...')
207
+ self.logger.info(f"About to send {component_name}...")
216
208
 
217
- if image_name == '__GlobalManifest__':
209
+ if image_name == "__GlobalManifest__":
218
210
  data = self.extract_global_manifest()
219
- elif image_name == '__RestoreVersion__':
211
+ elif image_name == "__RestoreVersion__":
220
212
  data = self.ipsw.restore_version
221
- elif image_name == '__SystemVersion__':
213
+ elif image_name == "__SystemVersion__":
222
214
  data = self.ipsw.system_version
223
215
  else:
224
216
  data = self.get_personalized_data(component_name, tss=self.recovery.tss)
225
217
 
226
- self.logger.info(f'Sending {component_name} now...')
218
+ self.logger.info(f"Sending {component_name} now...")
227
219
  chunk_size = 8192
228
220
  for i in trange(0, len(data), chunk_size, dynamic_ncols=True):
229
- await service.aio_send_plist({'FileData': data[i:i + chunk_size]})
221
+ await service.aio_send_plist({"FileData": data[i : i + chunk_size]})
230
222
 
231
223
  # Send FileDataDone
232
- await service.aio_send_plist({'FileDataDone': True})
224
+ await service.aio_send_plist({"FileDataDone": True})
233
225
 
234
- self.logger.info(f'Done sending {component_name}')
226
+ self.logger.info(f"Done sending {component_name}")
235
227
 
236
228
  async def send_source_boot_object_v4(self, message: dict) -> None:
237
- self.logger.debug('send_source_boot_object_v4')
229
+ self.logger.debug("send_source_boot_object_v4")
238
230
  service = await self._get_service_for_data_request(message)
239
- image_name = message['Arguments']['ImageName']
231
+ image_name = message["Arguments"]["ImageName"]
240
232
  component_name = image_name
241
- self.logger.info(f'About to send {component_name}...')
233
+ self.logger.info(f"About to send {component_name}...")
242
234
 
243
- if image_name == '__GlobalManifest__':
235
+ if image_name == "__GlobalManifest__":
244
236
  data = self.extract_global_manifest()
245
- elif image_name == '__RestoreVersion__':
237
+ elif image_name == "__RestoreVersion__":
246
238
  data = self.ipsw.restore_version
247
- elif image_name == '__SystemVersion__':
239
+ elif image_name == "__SystemVersion__":
248
240
  data = self.ipsw.system_version
249
241
  else:
250
- data = (self.get_build_identity_from_request(message)
251
- .get_component(component_name, tss=self.recovery.tss).data)
242
+ data = (
243
+ self.get_build_identity_from_request(message).get_component(component_name, tss=self.recovery.tss).data
244
+ )
252
245
 
253
- self.logger.info(f'Sending {component_name} now...')
246
+ self.logger.info(f"Sending {component_name} now...")
254
247
  chunk_size = 8192
255
248
  for i in trange(0, len(data), chunk_size, dynamic_ncols=True):
256
- chunk = data[i:i + chunk_size]
257
- await service.aio_send_plist({'FileData': chunk})
258
- if i == 0 and chunk.startswith(b'AEA1'):
259
- self.logger.debug('First chunk in a AEA')
249
+ chunk = data[i : i + chunk_size]
250
+ await service.aio_send_plist({"FileData": chunk})
251
+ if i == 0 and chunk.startswith(b"AEA1"):
252
+ self.logger.debug("First chunk in a AEA")
260
253
  try:
261
254
  message = await asyncio.wait_for(service.aio_recv_plist(), timeout=3)
262
- if message['MsgType'] != 'URLAsset':
255
+ if message["MsgType"] != "URLAsset":
263
256
  raise asyncio.exceptions.TimeoutError()
264
257
  await self.send_url_asset(message)
265
258
  except asyncio.exceptions.TimeoutError:
266
- self.logger.debug('No URLAsset was requested. Assuming it is not necessary')
259
+ self.logger.debug("No URLAsset was requested. Assuming it is not necessary")
267
260
 
268
261
  # Send FileDataDone
269
- await service.aio_send_plist({'FileDataDone': True})
262
+ await service.aio_send_plist({"FileDataDone": True})
270
263
 
271
- self.logger.info(f'Done sending {component_name}')
264
+ self.logger.info(f"Done sending {component_name}")
272
265
 
273
266
  async def get_recovery_os_local_policy_tss_response(self, args, build_identity=None):
274
267
  if build_identity is None:
@@ -276,29 +269,29 @@ class Restore(BaseRestore):
276
269
 
277
270
  # populate parameters
278
271
  parameters = {
279
- 'ApECID': self.device.ecid,
280
- 'Ap,LocalBoot': True,
281
- 'ApProductionMode': True,
282
- 'ApSecurityMode': True,
283
- 'ApSupportsImg4': True,
272
+ "ApECID": self.device.ecid,
273
+ "Ap,LocalBoot": True,
274
+ "ApProductionMode": True,
275
+ "ApSecurityMode": True,
276
+ "ApSupportsImg4": True,
284
277
  }
285
278
 
286
279
  build_identity.populate_tss_request_parameters(parameters)
287
280
 
288
281
  # Add Ap,LocalPolicy
289
282
  lpol = {
290
- 'Digest': hashlib.sha384(lpol_file).digest(),
291
- 'Trusted': True,
283
+ "Digest": hashlib.sha384(lpol_file).digest(),
284
+ "Trusted": True,
292
285
  }
293
286
 
294
- parameters['Ap,LocalPolicy'] = lpol
287
+ parameters["Ap,LocalPolicy"] = lpol
295
288
 
296
- parameters['Ap,NextStageIM4MHash'] = args['Ap,NextStageIM4MHash']
297
- parameters['Ap,RecoveryOSPolicyNonceHash'] = args['Ap,RecoveryOSPolicyNonceHash']
289
+ parameters["Ap,NextStageIM4MHash"] = args["Ap,NextStageIM4MHash"]
290
+ parameters["Ap,RecoveryOSPolicyNonceHash"] = args["Ap,RecoveryOSPolicyNonceHash"]
298
291
 
299
- vol_uuid = args['Ap,VolumeUUID']
300
- vol_uuid = binascii.unhexlify(vol_uuid.replace('-', ''))
301
- parameters['Ap,VolumeUUID'] = vol_uuid
292
+ vol_uuid = args["Ap,VolumeUUID"]
293
+ vol_uuid = binascii.unhexlify(vol_uuid.replace("-", ""))
294
+ parameters["Ap,VolumeUUID"] = vol_uuid
302
295
 
303
296
  # create basic request
304
297
  request = TSSRequest()
@@ -306,7 +299,7 @@ class Restore(BaseRestore):
306
299
  # add common tags from manifest
307
300
  request.add_local_policy_tags(parameters)
308
301
 
309
- self.logger.info('Requesting SHSH blobs...')
302
+ self.logger.info("Requesting SHSH blobs...")
310
303
  return await request.send_receive()
311
304
 
312
305
  def get_build_identity(self, is_recovery_os: bool):
@@ -320,24 +313,25 @@ class Restore(BaseRestore):
320
313
  return self.ipsw.build_manifest.get_build_identity(self.device.hardware_model, variant=variant)
321
314
 
322
315
  async def send_restore_local_policy(self, message: dict) -> None:
323
- component = 'Ap,LocalPolicy'
316
+ component = "Ap,LocalPolicy"
324
317
  service = await self._get_service_for_data_request(message)
325
318
 
326
319
  # The Update mode does not have a specific build identity for the recovery os.
327
320
  build_identity = self.get_build_identity(self.build_identity.restore_behavior == Behavior.Erase.value)
328
- tss_localpolicy = await self.get_recovery_os_local_policy_tss_response(message['Arguments'],
329
- build_identity=build_identity)
321
+ tss_localpolicy = await self.get_recovery_os_local_policy_tss_response(
322
+ message["Arguments"], build_identity=build_identity
323
+ )
330
324
 
331
325
  await service.aio_send_plist({
332
- 'Ap,LocalPolicy':
333
- self.get_personalized_data(component, data=lpol_file, tss=tss_localpolicy)})
326
+ "Ap,LocalPolicy": self.get_personalized_data(component, data=lpol_file, tss=tss_localpolicy)
327
+ })
334
328
 
335
329
  async def send_recovery_os_root_ticket(self, message: dict) -> None:
336
- self.logger.info('About to send RecoveryOSRootTicket...')
330
+ self.logger.info("About to send RecoveryOSRootTicket...")
337
331
  service = await self._get_service_for_data_request(message)
338
332
 
339
333
  if self.recovery.tss_recoveryos_root_ticket is None:
340
- raise PyMobileDevice3Exception('Cannot send RootTicket without TSS')
334
+ raise PyMobileDevice3Exception("Cannot send RootTicket without TSS")
341
335
 
342
336
  if self.device.is_image4_supported:
343
337
  data = self.recovery.tss_recoveryos_root_ticket.ap_img4_ticket
@@ -346,73 +340,70 @@ class Restore(BaseRestore):
346
340
 
347
341
  req = {}
348
342
  if data:
349
- req['RootTicketData'] = data
343
+ req["RootTicketData"] = data
350
344
  else:
351
- self.logger.warning('not sending RootTicketData (no data present)')
345
+ self.logger.warning("not sending RootTicketData (no data present)")
352
346
 
353
- self.logger.info('Sending RecoveryOSRootTicket now...')
347
+ self.logger.info("Sending RecoveryOSRootTicket now...")
354
348
  await service.aio_send_plist(req)
355
349
 
356
350
  async def send_root_ticket(self, message: dict) -> None:
357
- self.logger.info('About to send RootTicket...')
351
+ self.logger.info("About to send RootTicket...")
358
352
  service = await self._get_service_for_data_request(message)
359
353
 
360
354
  if self.recovery.tss is None:
361
- raise PyMobileDevice3Exception('Cannot send RootTicket without TSS')
355
+ raise PyMobileDevice3Exception("Cannot send RootTicket without TSS")
362
356
 
363
- self.logger.info('Sending RootTicket now...')
364
- await service.aio_send_plist({'RootTicketData': self.recovery.tss.ap_img4_ticket})
357
+ self.logger.info("Sending RootTicket now...")
358
+ await service.aio_send_plist({"RootTicketData": self.recovery.tss.ap_img4_ticket})
365
359
 
366
360
  async def send_nor(self, message: dict):
367
- self.logger.info('About to send NORData...')
361
+ self.logger.info("About to send NORData...")
368
362
  service = await self._get_service_for_data_request(message)
369
363
 
370
364
  flash_version_1 = False
371
- llb_path = self.build_identity.get_component('LLB', tss=self.recovery.tss).path
372
- llb_filename_offset = llb_path.find('LLB')
365
+ llb_path = self.build_identity.get_component("LLB", tss=self.recovery.tss).path
366
+ llb_filename_offset = llb_path.find("LLB")
373
367
 
374
- arguments = message.get('Arguments')
368
+ arguments = message.get("Arguments")
375
369
  if arguments:
376
- flash_version_1 = arguments.get('FlashVersion1', False)
370
+ flash_version_1 = arguments.get("FlashVersion1", False)
377
371
 
378
372
  if llb_filename_offset == -1:
379
- raise PyMobileDevice3Exception('Unable to extract firmware path from LLB filename')
373
+ raise PyMobileDevice3Exception("Unable to extract firmware path from LLB filename")
380
374
 
381
- firmware_path = llb_path[:llb_filename_offset - 1]
382
- self.logger.info(f'Found firmware path: {firmware_path}')
375
+ firmware_path = llb_path[: llb_filename_offset - 1]
376
+ self.logger.info(f"Found firmware path: {firmware_path}")
383
377
 
384
- firmware_files = dict()
378
+ firmware_files = {}
385
379
  try:
386
380
  firmware = self.ipsw.get_firmware(firmware_path)
387
381
  firmware_files = firmware.get_files()
388
382
  except KeyError:
389
- self.logger.info('Getting firmware manifest from build identity')
390
- build_id_manifest = self.build_identity['Manifest']
383
+ self.logger.info("Getting firmware manifest from build identity")
384
+ build_id_manifest = self.build_identity["Manifest"]
391
385
  for component, manifest_entry in build_id_manifest.items():
392
386
  if isinstance(manifest_entry, dict):
393
- is_fw = plist_access_path(manifest_entry, ('Info', 'IsFirmwarePayload'), bool)
394
- loaded_by_iboot = plist_access_path(manifest_entry, ('Info', 'IsLoadedByiBoot'), bool)
395
- is_secondary_fw = plist_access_path(manifest_entry, ('Info', 'IsSecondaryFirmwarePayload'), bool)
387
+ is_fw = plist_access_path(manifest_entry, ("Info", "IsFirmwarePayload"), bool)
388
+ loaded_by_iboot = plist_access_path(manifest_entry, ("Info", "IsLoadedByiBoot"), bool)
389
+ is_secondary_fw = plist_access_path(manifest_entry, ("Info", "IsSecondaryFirmwarePayload"), bool)
396
390
 
397
391
  if is_fw or (is_secondary_fw and loaded_by_iboot):
398
- comp_path = plist_access_path(manifest_entry, ('Info', 'Path'))
392
+ comp_path = plist_access_path(manifest_entry, ("Info", "Path"))
399
393
  if comp_path:
400
394
  firmware_files[component] = comp_path
401
395
 
402
396
  if not firmware_files:
403
- raise PyMobileDevice3Exception('Unable to get list of firmware files.')
397
+ raise PyMobileDevice3Exception("Unable to get list of firmware files.")
404
398
 
405
- component = 'LLB'
399
+ component = "LLB"
406
400
  llb_data = self.get_personalized_data(component, tss=self.recovery.tss, path=llb_path)
407
- req = {'LlbImageData': llb_data}
401
+ req = {"LlbImageData": llb_data}
408
402
 
409
- if flash_version_1:
410
- norimage = {}
411
- else:
412
- norimage = []
403
+ norimage = {} if flash_version_1 else []
413
404
 
414
405
  for component, comppath in firmware_files.items():
415
- if component in ('LLB', 'RestoreSEP'):
406
+ if component in ("LLB", "RestoreSEP"):
416
407
  # skip LLB, it's already passed in LlbImageData
417
408
  # skip RestoreSEP, it's passed in RestoreSEPImageData
418
409
  continue
@@ -423,56 +414,56 @@ class Restore(BaseRestore):
423
414
  norimage[component] = nor_data
424
415
  else:
425
416
  # make sure iBoot is the first entry in the array
426
- if component.startswith('iBoot'):
427
- norimage = [nor_data] + norimage
417
+ if component.startswith("iBoot"):
418
+ norimage = [nor_data, *norimage]
428
419
  else:
429
420
  norimage.append(nor_data)
430
421
 
431
- req['NorImageData'] = norimage
422
+ req["NorImageData"] = norimage
432
423
 
433
- for component in ('RestoreSEP', 'SEP', 'SepStage1'):
424
+ for component in ("RestoreSEP", "SEP", "SepStage1"):
434
425
  if not self.build_identity.has_component(component):
435
426
  continue
436
427
  comp = self.build_identity.get_component(component, tss=self.recovery.tss)
437
428
  if comp.path:
438
- if component == 'SepStage1':
439
- component = 'SEPPatch'
440
- req[f'{component}ImageData'] = self.get_personalized_data(comp.name, comp.data, self.recovery.tss)
429
+ if component == "SepStage1":
430
+ component = "SEPPatch"
431
+ req[f"{component}ImageData"] = self.get_personalized_data(comp.name, comp.data, self.recovery.tss)
441
432
 
442
- self.logger.info('Sending NORData now...')
433
+ self.logger.info("Sending NORData now...")
443
434
  await service.aio_send_plist(req)
444
435
 
445
436
  @staticmethod
446
437
  def get_bbfw_fn_for_element(elem: str, bb_chip_id: Optional[int] = None) -> str:
447
438
  bbfw_fn_elem = {
448
439
  # ICE3 firmware files
449
- 'RamPSI': 'psi_ram.fls',
450
- 'FlashPSI': 'psi_flash.fls',
440
+ "RamPSI": "psi_ram.fls",
441
+ "FlashPSI": "psi_flash.fls",
451
442
  # Trek firmware files
452
- 'eDBL': 'dbl.mbn',
453
- 'RestoreDBL': 'restoredbl.mbn',
443
+ "eDBL": "dbl.mbn",
444
+ "RestoreDBL": "restoredbl.mbn",
454
445
  # Phoenix/Mav4 firmware files
455
- 'DBL': 'dbl.mbn',
456
- 'ENANDPRG': 'ENPRG.mbn',
446
+ "DBL": "dbl.mbn",
447
+ "ENANDPRG": "ENPRG.mbn",
457
448
  # Mav5 firmware files
458
- 'RestoreSBL1': 'restoresbl1.mbn',
459
- 'SBL1': 'sbl1.mbn',
449
+ "RestoreSBL1": "restoresbl1.mbn",
450
+ "SBL1": "sbl1.mbn",
460
451
  # ICE16 firmware files
461
- 'RestorePSI': 'restorepsi.bin',
462
- 'PSI': 'psi_ram.bin',
452
+ "RestorePSI": "restorepsi.bin",
453
+ "PSI": "psi_ram.bin",
463
454
  # ICE19 firmware files
464
- 'RestorePSI2': 'restorepsi2.bin',
465
- 'PSI2': 'psi_ram2.bin',
455
+ "RestorePSI2": "restorepsi2.bin",
456
+ "PSI2": "psi_ram2.bin",
466
457
  # Mav20 Firmware file
467
- 'Misc': 'multi_image.mbn',
458
+ "Misc": "multi_image.mbn",
468
459
  }
469
460
 
470
461
  bbfw_fn_elem_mav25 = {
471
462
  # Mav25 Firmware files
472
- 'Misc': 'multi_image.mbn',
473
- 'RestoreSBL1': 'restorexbl_sc.elf',
474
- 'SBL1': 'xbl_sc.elf',
475
- 'TME': 'signed_firmware_soc_view.elf',
463
+ "Misc": "multi_image.mbn",
464
+ "RestoreSBL1": "restorexbl_sc.elf",
465
+ "SBL1": "xbl_sc.elf",
466
+ "TME": "signed_firmware_soc_view.elf",
476
467
  }
477
468
 
478
469
  return bbfw_fn_elem_mav25.get(elem) if bb_chip_id == 0x1F30E1 else bbfw_fn_elem.get(elem)
@@ -486,11 +477,12 @@ class Restore(BaseRestore):
486
477
  def fls_insert_ticket(self, fls, bbticket):
487
478
  raise NotImplementedError()
488
479
 
489
- def sign_bbfw(self, bbfw_orig: bytes, bbtss: TSSResponse, bb_nonce: Optional[bytes],
490
- bb_chip_id: Optional[int] = None) -> bytes:
480
+ def sign_bbfw(
481
+ self, bbfw_orig: bytes, bbtss: TSSResponse, bb_nonce: Optional[bytes], bb_chip_id: Optional[int] = None
482
+ ) -> bytes:
491
483
  # check for BBTicket in result
492
484
  bbticket = bbtss.bb_ticket
493
- bbfw_dict = bbtss.get('BasebandFirmware')
485
+ bbfw_dict = bbtss.get("BasebandFirmware")
494
486
  is_fls = False
495
487
  signed_file = []
496
488
 
@@ -499,100 +491,100 @@ class Restore(BaseRestore):
499
491
  tmp_zip_read_name = tmp_zip_read.name
500
492
 
501
493
  try:
502
- with zipfile.ZipFile(tmp_zip_read_name, 'r') as bbfw_orig:
503
- with tempfile.NamedTemporaryFile() as tmp_zip_write:
504
- bbfw_patched = zipfile.ZipFile(tmp_zip_write, 'w')
494
+ with zipfile.ZipFile(tmp_zip_read_name, "r") as bbfw_orig, tempfile.NamedTemporaryFile() as tmp_zip_write:
495
+ bbfw_patched = zipfile.ZipFile(tmp_zip_write, "w")
505
496
 
506
- for key, blob in bbfw_dict.items():
507
- if key.endswith('-Blob') and isinstance(blob, bytes):
508
- key = key.split('-', 1)[0]
509
- signfn = self.get_bbfw_fn_for_element(key, bb_chip_id)
497
+ for key, blob in bbfw_dict.items():
498
+ if key.endswith("-Blob") and isinstance(blob, bytes):
499
+ key = key.split("-", 1)[0]
500
+ signfn = self.get_bbfw_fn_for_element(key, bb_chip_id)
510
501
 
511
- if signfn is None:
512
- raise PyMobileDevice3Exception(
513
- f'can\'t match element name \'{key}\' to baseband firmware file name.')
502
+ if signfn is None:
503
+ raise PyMobileDevice3Exception(
504
+ f"can't match element name '{key}' to baseband firmware file name."
505
+ )
514
506
 
515
- if signfn.endswith('.fls'):
516
- is_fls = True
507
+ if signfn.endswith(".fls"):
508
+ is_fls = True
517
509
 
518
- buffer = bbfw_orig.read(signfn)
510
+ buffer = bbfw_orig.read(signfn)
519
511
 
520
- if is_fls:
521
- raise NotImplementedError('is_fls')
522
- elif bb_chip_id == 0x1F30E1: # Mav25 - Qualcomm Snapdragon X80 5G Modem
523
- data = mbn_mav25_stitch(buffer, blob)
524
- else:
525
- data = mbn_stitch(buffer, blob)
512
+ if is_fls:
513
+ raise NotImplementedError("is_fls")
514
+ elif bb_chip_id == 0x1F30E1: # Mav25 - Qualcomm Snapdragon X80 5G Modem
515
+ data = mbn_mav25_stitch(buffer, blob)
516
+ else:
517
+ data = mbn_stitch(buffer, blob)
526
518
 
527
- bbfw_patched.writestr(bbfw_orig.getinfo(signfn), data)
519
+ bbfw_patched.writestr(bbfw_orig.getinfo(signfn), data)
528
520
 
529
- if is_fls and (bb_nonce is None):
530
- if key == 'RamPSI':
531
- signed_file.append(signfn)
532
- else:
521
+ if is_fls and (bb_nonce is None):
522
+ if key == "RamPSI":
533
523
  signed_file.append(signfn)
534
-
535
- # remove everything but required files
536
- for entry in bbfw_orig.filelist:
537
- keep = False
538
- filename = entry.filename
539
-
540
- if filename in signed_file:
541
- keep = True
542
-
543
- # check for anything but .mbn and .fls if bb_nonce is set
544
- if bb_nonce and not keep:
545
- ext = os.path.splitext(filename)[1]
546
- keep |= ext in ('.fls', '.mbn', '.elf', '.bin')
547
-
548
- if keep and (filename not in signed_file):
549
- bbfw_patched.writestr(bbfw_orig.getinfo(filename), bbfw_orig.read(filename))
550
-
551
- if bb_nonce:
552
- if is_fls:
553
- # add BBTicket to file ebl.fls
554
- buffer = bbfw_orig.read('ebl.fls')
555
- fls = self.fls_parse(buffer)
556
- data = self.fls_insert_ticket(fls, bbticket)
557
- bbfw_patched.writestr('ebl.fls', data)
558
524
  else:
559
- # add BBTicket as bbticket.der
560
- zname = zipfile.ZipInfo('bbticket.der')
561
- zname.filename = 'bbticket.der'
562
- ZIP_EXT_ATTR_FILE = 0o100000
563
- zname.external_attr = (0o644 | ZIP_EXT_ATTR_FILE) << 16
564
- bbfw_patched.writestr(zname, bbticket)
565
-
566
- bbfw_patched.close()
567
- tmp_zip_write.seek(0)
568
- return tmp_zip_write.read()
525
+ signed_file.append(signfn)
526
+
527
+ # remove everything but required files
528
+ for entry in bbfw_orig.filelist:
529
+ keep = False
530
+ filename = entry.filename
531
+
532
+ if filename in signed_file:
533
+ keep = True
534
+
535
+ # check for anything but .mbn and .fls if bb_nonce is set
536
+ if bb_nonce and not keep:
537
+ ext = os.path.splitext(filename)[1]
538
+ keep |= ext in (".fls", ".mbn", ".elf", ".bin")
539
+
540
+ if keep and (filename not in signed_file):
541
+ bbfw_patched.writestr(bbfw_orig.getinfo(filename), bbfw_orig.read(filename))
542
+
543
+ if bb_nonce:
544
+ if is_fls:
545
+ # add BBTicket to file ebl.fls
546
+ buffer = bbfw_orig.read("ebl.fls")
547
+ fls = self.fls_parse(buffer)
548
+ data = self.fls_insert_ticket(fls, bbticket)
549
+ bbfw_patched.writestr("ebl.fls", data)
550
+ else:
551
+ # add BBTicket as bbticket.der
552
+ zname = zipfile.ZipInfo("bbticket.der")
553
+ zname.filename = "bbticket.der"
554
+ ZIP_EXT_ATTR_FILE = 0o100000
555
+ zname.external_attr = (0o644 | ZIP_EXT_ATTR_FILE) << 16
556
+ bbfw_patched.writestr(zname, bbticket)
557
+
558
+ bbfw_patched.close()
559
+ tmp_zip_write.seek(0)
560
+ return tmp_zip_write.read()
569
561
  finally:
570
562
  if tmp_zip_read_name:
571
563
  os.remove(tmp_zip_read_name)
572
564
 
573
565
  @asyncio_print_traceback
574
566
  async def send_baseband_data(self, message: dict):
575
- self.logger.info(f'About to send BasebandData: {message}')
567
+ self.logger.info(f"About to send BasebandData: {message}")
576
568
  service = await self._get_service_for_data_request(message)
577
569
 
578
570
  # NOTE: this function is called 2 or 3 times!
579
571
 
580
572
  # setup request data
581
- arguments = message['Arguments']
582
- bb_chip_id = arguments.get('ChipID')
583
- bb_cert_id = arguments.get('CertID')
584
- bb_snum = arguments.get('ChipSerialNo')
585
- bb_nonce = arguments.get('Nonce')
573
+ arguments = message["Arguments"]
574
+ bb_chip_id = arguments.get("ChipID")
575
+ bb_cert_id = arguments.get("CertID")
576
+ bb_snum = arguments.get("ChipSerialNo")
577
+ bb_nonce = arguments.get("Nonce")
586
578
  bbtss = self.bbtss
587
579
 
588
580
  if (bb_nonce is None) or (self.bbtss is None):
589
581
  # populate parameters
590
- parameters = {'ApECID': self.device.ecid}
582
+ parameters = {"ApECID": self.device.ecid}
591
583
  if bb_nonce:
592
- parameters['BbNonce'] = bb_nonce
593
- parameters['BbChipID'] = bb_chip_id
594
- parameters['BbGoldCertId'] = bb_cert_id
595
- parameters['BbSNUM'] = bb_snum
584
+ parameters["BbNonce"] = bb_nonce
585
+ parameters["BbChipID"] = bb_chip_id
586
+ parameters["BbGoldCertId"] = bb_cert_id
587
+ parameters["BbSNUM"] = bb_snum
596
588
 
597
589
  self.populate_tss_request_from_manifest(parameters)
598
590
 
@@ -603,11 +595,11 @@ class Restore(BaseRestore):
603
595
  request.add_common_tags(parameters)
604
596
  request.add_baseband_tags(parameters)
605
597
 
606
- fdr_support = self.build_identity['Info'].get('FDRSupport', False)
598
+ fdr_support = self.build_identity["Info"].get("FDRSupport", False)
607
599
  if fdr_support:
608
- request.update({'ApProductionMode': True, 'ApSecurityMode': True})
600
+ request.update({"ApProductionMode": True, "ApSecurityMode": True})
609
601
 
610
- self.logger.info('Sending Baseband TSS request...')
602
+ self.logger.info("Sending Baseband TSS request...")
611
603
  bbtss = await request.send_receive()
612
604
 
613
605
  if bb_nonce:
@@ -615,124 +607,127 @@ class Restore(BaseRestore):
615
607
  self.bbtss = bbtss
616
608
 
617
609
  # get baseband firmware file path from build identity
618
- bbfwpath = self.build_identity['Manifest']['BasebandFirmware']['Info']['Path']
610
+ bbfwpath = self.build_identity["Manifest"]["BasebandFirmware"]["Info"]["Path"]
619
611
 
620
612
  # extract baseband firmware to temp file
621
613
  bbfw = self.ipsw.read(bbfwpath)
622
614
 
623
615
  buffer = self.sign_bbfw(bbfw, bbtss, bb_nonce, bb_chip_id)
624
616
 
625
- self.logger.info('Sending BasebandData now...')
626
- await service.aio_send_plist({'BasebandData': buffer})
617
+ self.logger.info("Sending BasebandData now...")
618
+ await service.aio_send_plist({"BasebandData": buffer})
627
619
 
628
620
  async def send_fdr_trust_data(self, message: dict) -> None:
629
- self.logger.info('About to send FDR Trust data...')
621
+ self.logger.info("About to send FDR Trust data...")
630
622
  service = await self._get_service_for_data_request(message)
631
623
 
632
624
  # FIXME: What should we send here?
633
625
  # Sending an empty dict makes it continue with FDR
634
626
  # and this is what iTunes seems to be doing too
635
- self.logger.info('Sending FDR Trust data now...')
627
+ self.logger.info("Sending FDR Trust data now...")
636
628
  await service.aio_send_plist({})
637
629
 
638
630
  async def send_image_data(
639
- self, message: dict, image_list_k: Optional[str], image_type_k: Optional[str],
640
- image_data_k: Optional[str]) -> None:
641
- self.logger.debug(f'send_image_data: {message}')
642
- arguments = message['Arguments']
631
+ self, message: dict, image_list_k: Optional[str], image_type_k: Optional[str], image_data_k: Optional[str]
632
+ ) -> None:
633
+ self.logger.debug(f"send_image_data: {message}")
634
+ arguments = message["Arguments"]
643
635
  want_image_list = arguments.get(image_list_k)
644
- image_name = arguments.get('ImageName')
645
- build_id_manifest = self.build_identity['Manifest']
646
-
647
- if not want_image_list and image_name is not None:
636
+ image_name = arguments.get("ImageName")
637
+ build_id_manifest = self.build_identity["Manifest"]
638
+
639
+ if (
640
+ (not want_image_list)
641
+ and (image_name is not None)
642
+ and (image_name not in build_id_manifest)
643
+ and (image_name.startswith("Ap"))
644
+ ):
645
+ image_name = image_name.replace("Ap", "Ap,")
648
646
  if image_name not in build_id_manifest:
649
- if image_name.startswith('Ap'):
650
- image_name = image_name.replace('Ap', 'Ap,')
651
- if image_name not in build_id_manifest:
652
- raise PyMobileDevice3Exception(f'{image_name} not in build_id_manifest')
647
+ raise PyMobileDevice3Exception(f"{image_name} not in build_id_manifest")
653
648
 
654
649
  if image_type_k is None:
655
- image_type_k = arguments['ImageType']
650
+ image_type_k = arguments["ImageType"]
656
651
 
657
652
  if image_type_k is None:
658
- raise PyMobileDevice3Exception('missing ImageType')
653
+ raise PyMobileDevice3Exception("missing ImageType")
659
654
 
660
655
  if want_image_list is None and image_name is None:
661
- self.logger.info(f'About to send {image_data_k}...')
656
+ self.logger.info(f"About to send {image_data_k}...")
662
657
 
663
658
  matched_images = []
664
- data_dict = dict()
659
+ data_dict = {}
665
660
 
666
661
  for component, manifest_entry in build_id_manifest.items():
667
662
  if not isinstance(manifest_entry, dict):
668
663
  continue
669
664
 
670
- is_image_type = manifest_entry['Info'].get(image_type_k)
665
+ is_image_type = manifest_entry["Info"].get(image_type_k)
671
666
  if is_image_type:
672
667
  if want_image_list:
673
- self.logger.info(f'found {component} component')
668
+ self.logger.info(f"found {component} component")
674
669
  matched_images.append(component)
675
670
  elif image_name is None or image_name == component:
676
671
  if image_name is None:
677
- self.logger.info(f'found {image_type_k} component \'{component}\'')
672
+ self.logger.info(f"found {image_type_k} component '{component}'")
678
673
  else:
679
- self.logger.info(f'found component \'{component}\'')
674
+ self.logger.info(f"found component '{component}'")
680
675
 
681
676
  data_dict[component] = self.get_personalized_data(component, tss=self.recovery.tss)
682
677
 
683
- req = dict()
678
+ req = {}
684
679
  if want_image_list:
685
680
  req[image_list_k] = matched_images
686
- self.logger.info(f'Sending {image_type_k} image list')
681
+ self.logger.info(f"Sending {image_type_k} image list")
687
682
  else:
688
683
  if image_name:
689
684
  if image_name in data_dict:
690
685
  req[image_data_k] = data_dict[image_name]
691
- req['ImageName'] = image_name
692
- self.logger.info(f'Sending {image_type_k} for {image_name}...')
686
+ req["ImageName"] = image_name
687
+ self.logger.info(f"Sending {image_type_k} for {image_name}...")
693
688
  else:
694
689
  req[image_data_k] = data_dict
695
- self.logger.info(f'Sending {image_type_k} now...')
690
+ self.logger.info(f"Sending {image_type_k} now...")
696
691
 
697
692
  await self._restored.send(req)
698
693
 
699
694
  async def send_bootability_bundle_data(self, message: dict) -> None:
700
- self.logger.debug(f'send_bootability_bundle_data: {message}')
695
+ self.logger.debug(f"send_bootability_bundle_data: {message}")
701
696
  service = await self._get_service_for_data_request(message)
702
697
  await service.aio_sendall(self.ipsw.bootability)
703
698
  await service.aio_close()
704
699
 
705
700
  async def send_manifest(self) -> None:
706
- self.logger.debug('send_manifest')
707
- await self._restored.send({'ReceiptManifest': self.build_identity.manifest})
701
+ self.logger.debug("send_manifest")
702
+ await self._restored.send({"ReceiptManifest": self.build_identity.manifest})
708
703
 
709
704
  async def get_se_firmware_data(self, updater_name: str, info: dict, arguments: dict) -> dict:
710
- chip_id = info.get('SE,ChipID')
705
+ chip_id = info.get("SE,ChipID")
711
706
  if chip_id is None:
712
- chip_id = self.build_identity['Manifest']['SE,ChipID']
707
+ chip_id = self.build_identity["Manifest"]["SE,ChipID"]
713
708
 
714
709
  if chip_id == 0x20211:
715
- comp_name = 'SE,Firmware'
716
- elif chip_id in (0x73, 0x64, 0xC8, 0xD2, 0x2c, 0x36, 0x37):
717
- comp_name = 'SE,UpdatePayload'
710
+ comp_name = "SE,Firmware"
711
+ elif chip_id in (0x73, 0x64, 0xC8, 0xD2, 0x2C, 0x36, 0x37):
712
+ comp_name = "SE,UpdatePayload"
718
713
  else:
719
- self.logger.warning(f'Unknown SE,ChipID {chip_id} detected. Restore might fail.')
714
+ self.logger.warning(f"Unknown SE,ChipID {chip_id} detected. Restore might fail.")
720
715
 
721
- if self.build_identity.has_component('SE,UpdatePayload'):
722
- comp_name = 'SE,UpdatePayload'
723
- elif self.build_identity.has_component('SE,Firmware'):
724
- comp_name = 'SE,Firmware'
716
+ if self.build_identity.has_component("SE,UpdatePayload"):
717
+ comp_name = "SE,UpdatePayload"
718
+ elif self.build_identity.has_component("SE,Firmware"):
719
+ comp_name = "SE,Firmware"
725
720
  else:
726
- raise NotImplementedError('Neither \'SE,Firmware\' nor \'SE,UpdatePayload\' found in build identity.')
721
+ raise NotImplementedError("Neither 'SE,Firmware' nor 'SE,UpdatePayload' found in build identity.")
727
722
 
728
723
  component_data = self.build_identity.get_component(comp_name).data
729
724
 
730
- if 'DeviceGeneratedTags' in arguments:
725
+ if "DeviceGeneratedTags" in arguments:
731
726
  response = self.get_device_generated_firmware_data(updater_name, info, arguments)
732
727
  else:
733
728
  # create SE request
734
729
  request = TSSRequest()
735
- parameters = dict()
730
+ parameters = {}
736
731
 
737
732
  # add manifest for current build_identity to parameters
738
733
  self.populate_tss_request_from_manifest(parameters)
@@ -743,22 +738,22 @@ class Restore(BaseRestore):
743
738
  # add required tags for SE TSS request
744
739
  request.add_se_tags(parameters, None)
745
740
 
746
- self.logger.info('Sending SE TSS request...')
741
+ self.logger.info("Sending SE TSS request...")
747
742
  response = await request.send_receive()
748
743
 
749
- if 'SE,Ticket' in response:
750
- self.logger.info('Received SE ticket')
744
+ if "SE,Ticket" in response:
745
+ self.logger.info("Received SE ticket")
751
746
  else:
752
- raise PyMobileDevice3Exception('No \'SE,Ticket\' in TSS response, this might not work')
747
+ raise PyMobileDevice3Exception("No 'SE,Ticket' in TSS response, this might not work")
753
748
 
754
- response['FirmwareData'] = component_data
749
+ response["FirmwareData"] = component_data
755
750
 
756
751
  return response
757
752
 
758
753
  async def get_yonkers_firmware_data(self, info: dict):
759
754
  # create Yonkers request
760
755
  request = TSSRequest()
761
- parameters = dict()
756
+ parameters = {}
762
757
 
763
758
  # add manifest for current build_identity to parameters
764
759
  self.populate_tss_request_from_manifest(parameters)
@@ -770,33 +765,33 @@ class Restore(BaseRestore):
770
765
  comp_name = request.add_yonkers_tags(parameters, None)
771
766
 
772
767
  if comp_name is None:
773
- raise PyMobileDevice3Exception('Could not determine Yonkers firmware component')
768
+ raise PyMobileDevice3Exception("Could not determine Yonkers firmware component")
774
769
 
775
- self.logger.debug(f'restore_get_yonkers_firmware_data: using {comp_name}')
770
+ self.logger.debug(f"restore_get_yonkers_firmware_data: using {comp_name}")
776
771
 
777
- self.logger.info('Sending SE Yonkers request...')
772
+ self.logger.info("Sending SE Yonkers request...")
778
773
  response = await request.send_receive()
779
774
 
780
- if 'Yonkers,Ticket' in response:
781
- self.logger.info('Received SE ticket')
775
+ if "Yonkers,Ticket" in response:
776
+ self.logger.info("Received SE ticket")
782
777
  else:
783
- raise PyMobileDevice3Exception('No \'Yonkers,Ticket\' in TSS response, this might not work')
778
+ raise PyMobileDevice3Exception("No 'Yonkers,Ticket' in TSS response, this might not work")
784
779
 
785
780
  # now get actual component data
786
781
  component_data = self.build_identity.get_component(comp_name).data
787
782
 
788
783
  firmware_data = {
789
- 'YonkersFirmware': component_data,
784
+ "YonkersFirmware": component_data,
790
785
  }
791
786
 
792
- response['FirmwareData'] = firmware_data
787
+ response["FirmwareData"] = firmware_data
793
788
 
794
789
  return response
795
790
 
796
791
  async def get_savage_firmware_data(self, info: dict):
797
792
  # create Savage request
798
793
  request = TSSRequest()
799
- parameters = dict()
794
+ parameters = {}
800
795
 
801
796
  # add manifest for current build_identity to parameters
802
797
  self.populate_tss_request_from_manifest(parameters)
@@ -808,47 +803,47 @@ class Restore(BaseRestore):
808
803
  comp_name = request.add_savage_tags(parameters, None)
809
804
 
810
805
  if comp_name is None:
811
- raise PyMobileDevice3Exception('Could not determine Savage firmware component')
806
+ raise PyMobileDevice3Exception("Could not determine Savage firmware component")
812
807
 
813
- self.logger.debug(f'restore_get_savage_firmware_data: using {comp_name}')
808
+ self.logger.debug(f"restore_get_savage_firmware_data: using {comp_name}")
814
809
 
815
- self.logger.info('Sending SE Savage request...')
810
+ self.logger.info("Sending SE Savage request...")
816
811
  response = await request.send_receive()
817
812
 
818
- if 'Savage,Ticket' in response:
819
- self.logger.info('Received SE ticket')
813
+ if "Savage,Ticket" in response:
814
+ self.logger.info("Received SE ticket")
820
815
  else:
821
- raise PyMobileDevice3Exception('No \'Savage,Ticket\' in TSS response, this might not work')
816
+ raise PyMobileDevice3Exception("No 'Savage,Ticket' in TSS response, this might not work")
822
817
 
823
818
  # now get actual component data
824
819
  component_data = self.build_identity.get_component(comp_name).data
825
- component_data = struct.pack('<L', len(component_data)) + b'\x00' * 12
820
+ component_data = struct.pack("<L", len(component_data)) + b"\x00" * 12
826
821
 
827
- response['FirmwareData'] = component_data
822
+ response["FirmwareData"] = component_data
828
823
 
829
824
  return response
830
825
 
831
826
  async def get_rose_firmware_data(self, updater_name: str, info: dict, arguments: dict):
832
- self.logger.info(f'get_rose_firmware_data: {info}')
827
+ self.logger.info(f"get_rose_firmware_data: {info}")
833
828
 
834
- if 'DeviceGeneratedTags' in arguments:
829
+ if "DeviceGeneratedTags" in arguments:
835
830
  response = self.get_device_generated_firmware_data(updater_name, info, arguments)
836
831
  return response
837
832
  else:
838
833
  # create Rose request
839
834
  request = TSSRequest()
840
- parameters = dict()
835
+ parameters = {}
841
836
 
842
837
  # add manifest for current build_identity to parameters
843
838
  self.populate_tss_request_from_manifest(parameters)
844
839
 
845
- parameters['ApProductionMode'] = True
840
+ parameters["ApProductionMode"] = True
846
841
 
847
842
  if self.device.is_image4_supported:
848
- parameters['ApSecurityMode'] = True
849
- parameters['ApSupportsImg4'] = True
843
+ parameters["ApSecurityMode"] = True
844
+ parameters["ApSupportsImg4"] = True
850
845
  else:
851
- parameters['ApSupportsImg4'] = False
846
+ parameters["ApSupportsImg4"] = False
852
847
 
853
848
  # add Rap,* tags from info dictionary to parameters
854
849
  parameters.update(info)
@@ -856,42 +851,42 @@ class Restore(BaseRestore):
856
851
  # add required tags for Rose TSS request
857
852
  request.add_rose_tags(parameters, None)
858
853
 
859
- self.logger.info('Sending Rose TSS request...')
854
+ self.logger.info("Sending Rose TSS request...")
860
855
  response = await request.send_receive()
861
856
 
862
- rose_ticket = response.get('Rap,Ticket')
857
+ rose_ticket = response.get("Rap,Ticket")
863
858
  if rose_ticket is None:
864
859
  self.logger.error('No "Rap,Ticket" in TSS response, this might not work')
865
860
 
866
- comp_name = 'Rap,RTKitOS'
861
+ comp_name = "Rap,RTKitOS"
867
862
  component_data = self.build_identity.get_component(comp_name).data
868
863
 
869
864
  ftab = Ftab(component_data)
870
865
 
871
- comp_name = 'Rap,RestoreRTKitOS'
866
+ comp_name = "Rap,RestoreRTKitOS"
872
867
  if self.build_identity.has_component(comp_name):
873
868
  rftab = Ftab(self.build_identity.get_component(comp_name).data)
874
869
 
875
- component_data = rftab.get_entry_data(b'rrko')
870
+ component_data = rftab.get_entry_data(b"rrko")
876
871
  if component_data is None:
877
872
  self.logger.error('Could not find "rrko" entry in ftab. This will probably break things')
878
873
  else:
879
- ftab.add_entry(b'rrko', component_data)
874
+ ftab.add_entry(b"rrko", component_data)
880
875
 
881
- response['FirmwareData'] = ftab.data
876
+ response["FirmwareData"] = ftab.data
882
877
 
883
878
  return response
884
879
 
885
880
  async def get_veridian_firmware_data(self, updater_name: str, info: dict, arguments: dict):
886
- self.logger.info(f'get_veridian_firmware_data: {info}')
887
- comp_name = 'BMU,FirmwareMap'
881
+ self.logger.info(f"get_veridian_firmware_data: {info}")
882
+ comp_name = "BMU,FirmwareMap"
888
883
 
889
- if 'DeviceGeneratedTags' in arguments:
884
+ if "DeviceGeneratedTags" in arguments:
890
885
  response = self.get_device_generated_firmware_data(updater_name, info, arguments)
891
886
  else:
892
887
  # create Veridian request
893
888
  request = TSSRequest()
894
- parameters = dict()
889
+ parameters = {}
895
890
 
896
891
  # add manifest for current build_identity to parameters
897
892
  self.populate_tss_request_from_manifest(parameters)
@@ -902,29 +897,29 @@ class Restore(BaseRestore):
902
897
  # add required tags for Veridian TSS request
903
898
  request.add_veridian_tags(parameters, None)
904
899
 
905
- self.logger.info('Sending Veridian TSS request...')
900
+ self.logger.info("Sending Veridian TSS request...")
906
901
  response = await request.send_receive()
907
902
 
908
- ticket = response.get('BMU,Ticket')
903
+ ticket = response.get("BMU,Ticket")
909
904
  if ticket is None:
910
905
  self.logger.warning('No "BMU,Ticket" in TSS response, this might not work')
911
906
 
912
907
  component_data = self.build_identity.get_component(comp_name).data
913
908
  fw_map = plistlib.loads(component_data)
914
- fw_map['fw_map_digest'] = self.build_identity['Manifest'][comp_name]['Digest']
909
+ fw_map["fw_map_digest"] = self.build_identity["Manifest"][comp_name]["Digest"]
915
910
 
916
911
  bin_plist = plistlib.dumps(fw_map, fmt=plistlib.PlistFormat.FMT_BINARY)
917
- response['FirmwareData'] = bin_plist
912
+ response["FirmwareData"] = bin_plist
918
913
 
919
914
  return response
920
915
 
921
916
  async def get_tcon_firmware_data(self, info: dict):
922
- self.logger.info(f'restore_get_tcon_firmware_data: {info}')
923
- comp_name = 'Baobab,TCON'
917
+ self.logger.info(f"restore_get_tcon_firmware_data: {info}")
918
+ comp_name = "Baobab,TCON"
924
919
 
925
920
  # create Baobab request
926
921
  request = TSSRequest()
927
- parameters = dict()
922
+ parameters = {}
928
923
 
929
924
  # add manifest for current build_identity to parameters
930
925
  self.populate_tss_request_from_manifest(parameters)
@@ -935,47 +930,46 @@ class Restore(BaseRestore):
935
930
  # add required tags for Baobab TSS request
936
931
  request.add_tcon_tags(parameters, None)
937
932
 
938
- self.logger.info('Sending Baobab TSS request...')
933
+ self.logger.info("Sending Baobab TSS request...")
939
934
  response = await request.send_receive()
940
935
 
941
- ticket = response.get('Baobab,Ticket')
936
+ ticket = response.get("Baobab,Ticket")
942
937
  if ticket is None:
943
938
  self.logger.warning('No "Baobab,Ticket" in TSS response, this might not work')
944
939
 
945
- response['FirmwareData'] = self.build_identity.get_component(comp_name).data
940
+ response["FirmwareData"] = self.build_identity.get_component(comp_name).data
946
941
 
947
942
  return response
948
943
 
949
944
  async def get_device_generated_firmware_data(self, updater_name: str, info: dict, arguments: dict) -> dict:
950
- self.logger.info(f'get_device_generated_firmware_data ({updater_name}): {arguments}')
945
+ self.logger.info(f"get_device_generated_firmware_data ({updater_name}): {arguments}")
951
946
  request = TSSRequest()
952
- parameters = dict()
947
+ parameters = {}
953
948
 
954
949
  # add manifest for current build_identity to parameters
955
- self.populate_tss_request_from_manifest(
956
- parameters, arguments['DeviceGeneratedTags']['BuildIdentityTags'])
950
+ self.populate_tss_request_from_manifest(parameters, arguments["DeviceGeneratedTags"]["BuildIdentityTags"])
957
951
 
958
- parameters['@BBTicket'] = True
959
- parameters['ApSecurityMode'] = True
952
+ parameters["@BBTicket"] = True
953
+ parameters["ApSecurityMode"] = True
960
954
 
961
955
  # by default, set it to True
962
- parameters['ApProductionMode'] = True
956
+ parameters["ApProductionMode"] = True
963
957
 
964
- for k, v in arguments['MessageArgInfo'].items():
965
- if k.endswith('ProductionMode'):
958
+ for k, v in arguments["MessageArgInfo"].items():
959
+ if k.endswith("ProductionMode"):
966
960
  # if ApProductionMode should be overridden
967
- parameters['ApProductionMode'] = bool(v)
961
+ parameters["ApProductionMode"] = bool(v)
968
962
 
969
- response_ticket = arguments['DeviceGeneratedTags']['ResponseTags'][0]
963
+ response_ticket = arguments["DeviceGeneratedTags"]["ResponseTags"][0]
970
964
 
971
- parameters.update(arguments['DeviceGeneratedRequest'])
965
+ parameters.update(arguments["DeviceGeneratedRequest"])
972
966
  request.add_common_tags(info)
973
967
  request.update(parameters)
974
968
 
975
- for redacted_field in ('RequiresUIDMode',):
969
+ for redacted_field in ("RequiresUIDMode",):
976
970
  request.remove_key(redacted_field)
977
971
 
978
- self.logger.info(f'Sending {updater_name} TSS request...')
972
+ self.logger.info(f"Sending {updater_name} TSS request...")
979
973
  response = await request.send_receive()
980
974
 
981
975
  ticket = response.get(response_ticket)
@@ -986,198 +980,201 @@ class Restore(BaseRestore):
986
980
  return response
987
981
 
988
982
  async def get_timer_firmware_data(self, info: dict):
989
- self.logger.info(f'get_timer_firmware_data: {info}')
983
+ self.logger.info(f"get_timer_firmware_data: {info}")
990
984
 
991
985
  ftab = None
992
986
 
993
987
  # create Timer request
994
988
  request = TSSRequest()
995
- parameters = dict()
989
+ parameters = {}
996
990
 
997
991
  # add manifest for current build_identity to parameters
998
992
  self.populate_tss_request_from_manifest(parameters)
999
993
 
1000
- parameters['ApProductionMode'] = True
994
+ parameters["ApProductionMode"] = True
1001
995
  if self.device.is_image4_supported:
1002
- parameters['ApSecurityMode'] = True
1003
- parameters['ApSupportsImg4'] = True
996
+ parameters["ApSecurityMode"] = True
997
+ parameters["ApSupportsImg4"] = True
1004
998
  else:
1005
- parameters['ApSupportsImg4'] = False
999
+ parameters["ApSupportsImg4"] = False
1006
1000
 
1007
1001
  # add Timer,* tags from info dictionary to parameters
1008
- info_array = info['InfoArray']
1002
+ info_array = info["InfoArray"]
1009
1003
  info_dict = info_array[0]
1010
- hwid = info_dict['HardwareID']
1011
- tag = info_dict['TagNumber']
1012
- parameters['TagNumber'] = tag
1013
- ticket_name = info_dict['TicketName']
1014
- parameters['TicketName'] = ticket_name
1015
- parameters[f'Timer,ChipID,{tag}'] = hwid['ChipID']
1016
- parameters[f'Timer,BoardID,{tag}'] = hwid['BoardID']
1017
- parameters[f'Timer,ECID,{tag}'] = hwid['ECID']
1018
- parameters[f'Timer,Nonce,{tag}'] = hwid['Nonce']
1019
- parameters[f'Timer,SecurityMode,{tag}'] = hwid['SecurityMode']
1020
- parameters[f'Timer,SecurityDomain,{tag}'] = hwid['SecurityDomain']
1021
- parameters[f'Timer,ProductionMode,{tag}'] = hwid['ProductionMode']
1022
-
1023
- ap_info = info['APInfo']
1004
+ hwid = info_dict["HardwareID"]
1005
+ tag = info_dict["TagNumber"]
1006
+ parameters["TagNumber"] = tag
1007
+ ticket_name = info_dict["TicketName"]
1008
+ parameters["TicketName"] = ticket_name
1009
+ parameters[f"Timer,ChipID,{tag}"] = hwid["ChipID"]
1010
+ parameters[f"Timer,BoardID,{tag}"] = hwid["BoardID"]
1011
+ parameters[f"Timer,ECID,{tag}"] = hwid["ECID"]
1012
+ parameters[f"Timer,Nonce,{tag}"] = hwid["Nonce"]
1013
+ parameters[f"Timer,SecurityMode,{tag}"] = hwid["SecurityMode"]
1014
+ parameters[f"Timer,SecurityDomain,{tag}"] = hwid["SecurityDomain"]
1015
+ parameters[f"Timer,ProductionMode,{tag}"] = hwid["ProductionMode"]
1016
+
1017
+ ap_info = info["APInfo"]
1024
1018
  parameters.update(ap_info)
1025
1019
 
1026
1020
  # add required tags for Timer TSS request
1027
1021
  request.add_timer_tags(parameters, None)
1028
1022
 
1029
- self.logger.info(f'Sending {ticket_name} TSS request...')
1023
+ self.logger.info(f"Sending {ticket_name} TSS request...")
1030
1024
  response = await request.send_receive()
1031
1025
 
1032
1026
  ticket = response.get(ticket_name)
1033
1027
  if ticket is None:
1034
1028
  self.logger.warning(f'No "{ticket_name}" in TSS response, this might not work')
1035
1029
 
1036
- comp_name = f'Timer,RTKitOS,{tag}'
1030
+ comp_name = f"Timer,RTKitOS,{tag}"
1037
1031
  if self.build_identity.has_component(comp_name):
1038
1032
  ftab = Ftab(self.build_identity.get_component(comp_name).data)
1039
- if ftab.tag != b'rkos':
1040
- self.logger.warning(f'Unexpected tag {ftab.tag}. continuing anyway.')
1033
+ if ftab.tag != b"rkos":
1034
+ self.logger.warning(f"Unexpected tag {ftab.tag}. continuing anyway.")
1041
1035
  else:
1042
1036
  self.logger.info(f'NOTE: Build identity does not have a "{comp_name}" component.')
1043
1037
 
1044
- comp_name = f'Timer,RestoreRTKitOS,{tag}'
1038
+ comp_name = f"Timer,RestoreRTKitOS,{tag}"
1045
1039
  if self.build_identity.has_component(comp_name):
1046
1040
  rftab = Ftab(self.build_identity.get_component(comp_name).data)
1047
1041
 
1048
- component_data = rftab.get_entry_data(b'rrko')
1042
+ component_data = rftab.get_entry_data(b"rrko")
1049
1043
  if component_data is None:
1050
1044
  self.logger.error('Could not find "rrko" entry in ftab. This will probably break things')
1051
1045
  else:
1052
1046
  if ftab is None:
1053
- raise PyMobileDevice3Exception('ftab is None')
1054
- ftab.add_entry(b'rrko', component_data)
1047
+ raise PyMobileDevice3Exception("ftab is None")
1048
+ ftab.add_entry(b"rrko", component_data)
1055
1049
  else:
1056
1050
  self.logger.info(f'NOTE: Build identity does not have a "{comp_name}" component.')
1057
1051
 
1058
- response['FirmwareData'] = ftab.data
1052
+ response["FirmwareData"] = ftab.data
1059
1053
 
1060
1054
  return response
1061
1055
 
1062
1056
  async def send_firmware_updater_data(self, message: dict):
1063
- self.logger.debug(f'got FirmwareUpdaterData request: {message}')
1057
+ self.logger.debug(f"got FirmwareUpdaterData request: {message}")
1064
1058
  service = await self._get_service_for_data_request(message)
1065
- arguments = message['Arguments']
1066
- s_type = arguments['MessageArgType']
1067
- updater_name = arguments['MessageArgUpdaterName']
1068
- device_generated_request = arguments.get('DeviceGeneratedRequest')
1059
+ arguments = message["Arguments"]
1060
+ s_type = arguments["MessageArgType"]
1061
+ updater_name = arguments["MessageArgUpdaterName"]
1062
+ device_generated_request = arguments.get("DeviceGeneratedRequest")
1069
1063
 
1070
- if s_type not in ('FirmwareResponseData',):
1071
- raise PyMobileDevice3Exception(f'MessageArgType has unexpected value \'{s_type}\'')
1064
+ if s_type not in ("FirmwareResponseData",):
1065
+ raise PyMobileDevice3Exception(f"MessageArgType has unexpected value '{s_type}'")
1072
1066
 
1073
- info = arguments['MessageArgInfo']
1067
+ info = arguments["MessageArgInfo"]
1074
1068
 
1075
1069
  if device_generated_request is not None:
1076
1070
  fwdict = await self.get_device_generated_firmware_data(updater_name, info, arguments)
1077
1071
  if fwdict is None:
1078
- raise PyMobileDevice3Exception(f'Couldn\'t get {updater_name} firmware data')
1072
+ raise PyMobileDevice3Exception(f"Couldn't get {updater_name} firmware data")
1079
1073
 
1080
- elif updater_name == 'SE':
1074
+ elif updater_name == "SE":
1081
1075
  fwdict = await self.get_se_firmware_data(updater_name, info, arguments)
1082
1076
  if fwdict is None:
1083
- raise PyMobileDevice3Exception('Couldn\'t get SE firmware data')
1077
+ raise PyMobileDevice3Exception("Couldn't get SE firmware data")
1084
1078
 
1085
- elif updater_name == 'Savage':
1086
- fwtype = 'Savage'
1087
- info2 = info.get('YonkersDeviceInfo')
1079
+ elif updater_name == "Savage":
1080
+ fwtype = "Savage"
1081
+ info2 = info.get("YonkersDeviceInfo")
1088
1082
  if info2:
1089
- fwtype = 'Yonkers'
1083
+ fwtype = "Yonkers"
1090
1084
  fwdict = await self.get_yonkers_firmware_data(info2)
1091
1085
  else:
1092
1086
  fwdict = await self.get_savage_firmware_data(info)
1093
1087
  if fwdict is None:
1094
- raise PyMobileDevice3Exception(f'Couldn\'t get {fwtype} firmware data')
1088
+ raise PyMobileDevice3Exception(f"Couldn't get {fwtype} firmware data")
1095
1089
 
1096
- elif updater_name == 'Rose':
1090
+ elif updater_name == "Rose":
1097
1091
  fwdict = await self.get_rose_firmware_data(updater_name, info, arguments)
1098
1092
  if fwdict is None:
1099
- raise PyMobileDevice3Exception('Couldn\'t get Rose firmware data')
1093
+ raise PyMobileDevice3Exception("Couldn't get Rose firmware data")
1100
1094
 
1101
- elif updater_name == 'T200':
1095
+ elif updater_name == "T200":
1102
1096
  fwdict = await self.get_veridian_firmware_data(updater_name, info, arguments)
1103
1097
  if fwdict is None:
1104
- raise PyMobileDevice3Exception('Couldn\'t get Veridian firmware data')
1098
+ raise PyMobileDevice3Exception("Couldn't get Veridian firmware data")
1105
1099
 
1106
- elif updater_name == 'AppleTCON':
1100
+ elif updater_name == "AppleTCON":
1107
1101
  fwdict = await self.get_tcon_firmware_data(info)
1108
1102
  if fwdict is None:
1109
- raise PyMobileDevice3Exception('Couldn\'t get TCON firmware data')
1103
+ raise PyMobileDevice3Exception("Couldn't get TCON firmware data")
1110
1104
 
1111
- elif updater_name == 'AppleTypeCRetimer':
1105
+ elif updater_name == "AppleTypeCRetimer":
1112
1106
  fwdict = await self.get_timer_firmware_data(info)
1113
1107
  if fwdict is None:
1114
- raise PyMobileDevice3Exception('Couldn\'t get AppleTypeCRetimer firmware data')
1108
+ raise PyMobileDevice3Exception("Couldn't get AppleTypeCRetimer firmware data")
1115
1109
 
1116
1110
  else:
1117
- raise PyMobileDevice3Exception(f'Got unknown updater name: {updater_name}')
1111
+ raise PyMobileDevice3Exception(f"Got unknown updater name: {updater_name}")
1118
1112
 
1119
- self.logger.info('Sending FirmwareResponse data now...')
1120
- await service.aio_send_plist({'FirmwareResponseData': fwdict})
1113
+ self.logger.info("Sending FirmwareResponse data now...")
1114
+ await service.aio_send_plist({"FirmwareResponseData": fwdict})
1121
1115
 
1122
1116
  async def send_firmware_updater_preflight(self, message: dict) -> None:
1123
- self.logger.warning(f'send_firmware_updater_preflight: {message}')
1117
+ self.logger.warning(f"send_firmware_updater_preflight: {message}")
1124
1118
  service = await self._get_service_for_data_request(message)
1125
1119
  await service.aio_send_plist({})
1126
1120
 
1127
1121
  async def send_url_asset(self, message: dict) -> None:
1128
- self.logger.info(f'send_url_asset: {message}')
1122
+ self.logger.info(f"send_url_asset: {message}")
1129
1123
  service = await self._get_service_for_data_request(message)
1130
- arguments = message['Arguments']
1131
- assert arguments['RequestMethod'] == 'GET'
1132
- url = arguments['RequestURL']
1124
+ arguments = message["Arguments"]
1125
+ assert arguments["RequestMethod"] == "GET"
1126
+ url = arguments["RequestURL"]
1133
1127
 
1134
1128
  if url in self._url_assets_cache:
1135
- self.logger.debug('Using cached URLAsset')
1129
+ self.logger.debug("Using cached URLAsset")
1136
1130
  response = self._url_assets_cache[url]
1137
1131
  else:
1138
1132
  loop = asyncio.get_event_loop()
1139
1133
  with ThreadPoolExecutor() as executor:
1140
1134
  response = await loop.run_in_executor(executor, requests.get, url)
1141
1135
  self._url_assets_cache[url] = response
1142
- await service.aio_send_plist({
1143
- 'ResponseBody': response.content,
1144
- 'ResponseBodyDone': True,
1145
- 'ResponseHeaders': dict(response.headers),
1146
- 'ResponseStatus': response.status_code,
1147
- }, fmt=plistlib.FMT_BINARY)
1136
+ await service.aio_send_plist(
1137
+ {
1138
+ "ResponseBody": response.content,
1139
+ "ResponseBodyDone": True,
1140
+ "ResponseHeaders": dict(response.headers),
1141
+ "ResponseStatus": response.status_code,
1142
+ },
1143
+ fmt=plistlib.FMT_BINARY,
1144
+ )
1148
1145
  await service.aio_close()
1149
1146
 
1150
1147
  async def send_streamed_image_decryption_key(self, message: dict) -> None:
1151
- self.logger.info(f'send_streamed_image_decryption_key: {message}')
1148
+ self.logger.info(f"send_streamed_image_decryption_key: {message}")
1152
1149
  service = await self._get_service_for_data_request(message)
1153
- arguments = message['Arguments']
1154
- assert arguments['RequestMethod'] == 'POST'
1150
+ arguments = message["Arguments"]
1151
+ assert arguments["RequestMethod"] == "POST"
1155
1152
 
1156
1153
  response = requests.post(
1157
- arguments['RequestURL'],
1158
- headers=arguments['RequestAdditionalHeaders'],
1159
- data=arguments['RequestBody'])
1160
- self.logger.info(f'response {response} {response.content}')
1154
+ arguments["RequestURL"], headers=arguments["RequestAdditionalHeaders"], data=arguments["RequestBody"]
1155
+ )
1156
+ self.logger.info(f"response {response} {response.content}")
1161
1157
  await service.aio_send_plist({
1162
- 'ResponseBody': response.content,
1163
- 'ResponseBodyDone': True,
1164
- 'ResponseHeaders': dict(response.headers),
1165
- 'ResponseStatus': response.status_code,
1158
+ "ResponseBody": response.content,
1159
+ "ResponseBodyDone": True,
1160
+ "ResponseHeaders": dict(response.headers),
1161
+ "ResponseStatus": response.status_code,
1166
1162
  })
1167
1163
 
1168
1164
  async def send_component(self, component: str, component_name: Optional[str] = None) -> None:
1169
1165
  if component_name is None:
1170
1166
  component_name = component
1171
1167
 
1172
- self.logger.info(f'Sending now {component_name}...')
1173
- await self._restored.send(
1174
- {f'{component_name}File': self.get_personalized_data(component, tss=self.recovery.tss)})
1168
+ self.logger.info(f"Sending now {component_name}...")
1169
+ await self._restored.send({
1170
+ f"{component_name}File": self.get_personalized_data(component, tss=self.recovery.tss)
1171
+ })
1175
1172
 
1176
1173
  async def handle_data_request_msg(self, message: dict):
1177
- self.logger.debug(f'handle_data_request_msg: {message}')
1174
+ self.logger.debug(f"handle_data_request_msg: {message}")
1178
1175
 
1179
1176
  # checks and see what kind of data restored is requests and pass the request to its own handler
1180
- data_type = message.get('DataType')
1177
+ data_type = message.get("DataType")
1181
1178
 
1182
1179
  if not isinstance(data_type, str):
1183
1180
  return
@@ -1186,41 +1183,41 @@ class Restore(BaseRestore):
1186
1183
  await self._data_request_handlers[data_type](message)
1187
1184
  elif data_type in self._data_request_components:
1188
1185
  await self._data_request_components[data_type](data_type)
1189
- elif data_type == 'SystemImageRootHash':
1190
- await self.send_component('SystemVolume', data_type)
1191
- elif data_type == 'SystemImageCanonicalMetadata':
1192
- await self.send_component('Ap,SystemVolumeCanonicalMetadata', data_type)
1193
- elif data_type == 'FUDData':
1194
- await self.send_image_data(message, 'FUDImageList', 'IsFUDFirmware', 'FUDImageData')
1195
- elif data_type == 'PersonalizedData':
1196
- await self.send_image_data(message, 'ImageList', None, 'ImageData')
1197
- elif data_type == 'EANData':
1198
- await self.send_image_data(message, 'EANImageList', 'IsEarlyAccessFirmware', 'EANData')
1199
- elif data_type == 'BootabilityBundle':
1186
+ elif data_type == "SystemImageRootHash":
1187
+ await self.send_component("SystemVolume", data_type)
1188
+ elif data_type == "SystemImageCanonicalMetadata":
1189
+ await self.send_component("Ap,SystemVolumeCanonicalMetadata", data_type)
1190
+ elif data_type == "FUDData":
1191
+ await self.send_image_data(message, "FUDImageList", "IsFUDFirmware", "FUDImageData")
1192
+ elif data_type == "PersonalizedData":
1193
+ await self.send_image_data(message, "ImageList", None, "ImageData")
1194
+ elif data_type == "EANData":
1195
+ await self.send_image_data(message, "EANImageList", "IsEarlyAccessFirmware", "EANData")
1196
+ elif data_type == "BootabilityBundle":
1200
1197
  await self.send_bootability_bundle_data(message)
1201
- elif data_type == 'ReceiptManifest':
1198
+ elif data_type == "ReceiptManifest":
1202
1199
  await self.send_manifest()
1203
- elif data_type == 'BasebandUpdaterOutputData':
1200
+ elif data_type == "BasebandUpdaterOutputData":
1204
1201
  await self.handle_baseband_updater_output_data(message)
1205
- elif data_type == 'HostSystemTime':
1202
+ elif data_type == "HostSystemTime":
1206
1203
  await self.handle_host_system_time(message)
1207
1204
  else:
1208
- self.logger.error(f'unknown data request: {message}')
1205
+ self.logger.error(f"unknown data request: {message}")
1209
1206
 
1210
1207
  async def handle_previous_restore_log_msg(self, message: dict):
1211
- restorelog = message['PreviousRestoreLog']
1212
- self.logger.debug(f'PreviousRestoreLog: {restorelog}')
1208
+ restorelog = message["PreviousRestoreLog"]
1209
+ self.logger.debug(f"PreviousRestoreLog: {restorelog}")
1213
1210
 
1214
1211
  async def handle_progress_msg(self, message: dict) -> None:
1215
- operation = message['Operation']
1212
+ operation = message["Operation"]
1216
1213
  if operation in PROGRESS_BAR_OPERATIONS:
1217
- message['Operation'] = PROGRESS_BAR_OPERATIONS[operation]
1214
+ message["Operation"] = PROGRESS_BAR_OPERATIONS[operation]
1218
1215
 
1219
- if message['Operation'] == 'VERIFY_RESTORE':
1220
- progress = message['Progress']
1216
+ if message["Operation"] == "VERIFY_RESTORE":
1217
+ progress = message["Progress"]
1221
1218
 
1222
1219
  if self._pb_verify_restore is None:
1223
- self._pb_verify_restore = tqdm(total=100, desc='verify-restore', dynamic_ncols=True)
1220
+ self._pb_verify_restore = tqdm(total=100, desc="verify-restore", dynamic_ncols=True)
1224
1221
  self._pb_verify_restore_old_value = 0
1225
1222
 
1226
1223
  self._pb_verify_restore.update(progress - self._pb_verify_restore_old_value)
@@ -1232,79 +1229,78 @@ class Restore(BaseRestore):
1232
1229
 
1233
1230
  return
1234
1231
 
1235
- self.logger.debug(f'progress-bar: {message}')
1232
+ self.logger.debug(f"progress-bar: {message}")
1236
1233
 
1237
1234
  async def handle_status_msg(self, message: dict):
1238
- self.logger.debug(f'status message: {message}')
1239
- status = message['Status']
1240
- log = message.get('Log')
1235
+ self.logger.debug(f"status message: {message}")
1236
+ status = message["Status"]
1237
+ log = message.get("Log")
1241
1238
 
1242
1239
  if log:
1243
1240
  # this is the true device log that may inform us for anything that went wrong
1244
- self.logger.debug(f'log:\n{log}\n')
1241
+ self.logger.debug(f"log:\n{log}\n")
1245
1242
 
1246
1243
  if status == 0:
1247
1244
  self._restore_finished = True
1248
- await self._restored.send({'MsgType': 'ReceivedFinalStatusMsg'})
1245
+ await self._restored.send({"MsgType": "ReceivedFinalStatusMsg"})
1249
1246
  else:
1250
1247
  if status in known_errors:
1251
1248
  self.logger.error(known_errors[status])
1252
1249
  else:
1253
- self.logger.error('unknown error')
1250
+ self.logger.error("unknown error")
1254
1251
 
1255
1252
  async def handle_checkpoint_msg(self, message: dict):
1256
- self.logger.debug(f'checkpoint: {message}')
1253
+ self.logger.debug(f"checkpoint: {message}")
1257
1254
 
1258
1255
  async def handle_bb_update_status_msg(self, message: dict):
1259
- self.logger.debug(f'bb_update_status_msg: {message}')
1260
- if not message['Accepted']:
1256
+ self.logger.debug(f"bb_update_status_msg: {message}")
1257
+ if not message["Accepted"]:
1261
1258
  raise PyMobileDevice3Exception(str(message))
1262
1259
 
1263
1260
  async def handle_baseband_updater_output_data(self, message: dict) -> None:
1264
- self.logger.debug(f'restore_handle_baseband_updater_output_data: {message}')
1265
- data_port = message['DataPort']
1261
+ self.logger.debug(f"restore_handle_baseband_updater_output_data: {message}")
1262
+ data_port = message["DataPort"]
1266
1263
 
1267
- self.logger.info('Connecting to baseband updater data port')
1264
+ self.logger.info("Connecting to baseband updater data port")
1268
1265
 
1269
1266
  while True:
1270
1267
  try:
1271
- client = ServiceConnection.create_using_usbmux(self._restored.udid, data_port,
1272
- connection_type='USB')
1268
+ client = ServiceConnection.create_using_usbmux(self._restored.udid, data_port, connection_type="USB")
1273
1269
  break
1274
1270
  except ConnectionFailedError:
1275
- self.logger.debug('Retrying connection...')
1271
+ self.logger.debug("Retrying connection...")
1276
1272
 
1277
1273
  if not client:
1278
- raise ConnectionFailedError(f'failed to establish connection to {data_port}')
1274
+ raise ConnectionFailedError(f"failed to establish connection to {data_port}")
1279
1275
 
1280
- self.logger.info('Connected to BasebandUpdaterOutputData data port')
1276
+ self.logger.info("Connected to BasebandUpdaterOutputData data port")
1281
1277
 
1282
- filename = f'updater_output-{self._restored.udid}.cpio'
1283
- self.logger.info(f'Writing updater output into: {filename}')
1278
+ filename = f"updater_output-{self._restored.udid}.cpio"
1279
+ self.logger.info(f"Writing updater output into: {filename}")
1284
1280
 
1285
- with open(filename, 'wb') as f:
1281
+ with open(filename, "wb") as f:
1286
1282
  while True:
1287
1283
  buf = client.recv()
1288
1284
  if not buf:
1289
1285
  break
1290
1286
  f.write(buf)
1291
1287
 
1292
- self.logger.debug('Closing connection of BasebandUpdaterOutputData data port')
1288
+ self.logger.debug("Closing connection of BasebandUpdaterOutputData data port")
1293
1289
  client.close()
1294
1290
 
1295
1291
  async def handle_host_system_time(self, message: dict) -> None:
1296
- await self._restored.send({'SetHostTimeOnDevice': time.time()})
1292
+ await self._restored.send({"SetHostTimeOnDevice": time.time()})
1297
1293
 
1298
1294
  async def handle_restored_crash(self, message: dict) -> None:
1299
- backtrace = '\n'.join(message['RestoredBacktrace'])
1300
- self.logger.info(f'restored crashed. backtrace:\n{backtrace}')
1295
+ backtrace = "\n".join(message["RestoredBacktrace"])
1296
+ self.logger.info(f"restored crashed. backtrace:\n{backtrace}")
1301
1297
 
1302
1298
  async def handle_async_wait(self, message: dict) -> None:
1303
1299
  self.logger.debug(message)
1304
1300
 
1305
1301
  async def handle_restore_attestation(self, message: dict) -> None:
1306
1302
  self.logger.debug(message)
1307
- await self._restored.send({'RestoreShouldAttest': False})
1303
+ await self._restored.send({"RestoreShouldAttest": False})
1308
1304
 
1309
1305
  async def _connect_to_restored_service(self):
1310
1306
  while True:
@@ -1315,33 +1311,38 @@ class Restore(BaseRestore):
1315
1311
  await asyncio.sleep(1)
1316
1312
 
1317
1313
  async def restore_device(self) -> None:
1318
- self.logger.debug('waiting for device to connect for restored service')
1314
+ self.logger.debug("waiting for device to connect for restored service")
1319
1315
  await self._connect_to_restored_service()
1320
1316
 
1321
- self.logger.info(f'hardware info: {self._restored.hardware_info}')
1322
- self.logger.info(f'version: {self._restored.version}')
1323
- self.logger.info(f'saved_debug_info: {self._restored.saved_debug_info}')
1317
+ self.logger.info(f"hardware info: {self._restored.hardware_info}")
1318
+ self.logger.info(f"version: {self._restored.version}")
1319
+ self.logger.info(f"saved_debug_info: {self._restored.saved_debug_info}")
1324
1320
 
1325
1321
  if self.recovery.tss.bb_ticket is not None:
1326
1322
  # initial TSS response contains a baseband ticket
1327
1323
  self.bbtss = self.recovery.tss
1328
1324
 
1329
1325
  if self._ignore_fdr:
1330
- self.logger.info('Establishing a mock FDR listener')
1326
+ self.logger.info("Establishing a mock FDR listener")
1331
1327
  self._fdr = ServiceConnection.create_using_usbmux(
1332
- self._restored.udid, FDRClient.SERVICE_PORT, connection_type='USB'
1328
+ self._restored.udid, FDRClient.SERVICE_PORT, connection_type="USB"
1333
1329
  )
1334
1330
  else:
1335
- self.logger.info('Starting FDR listener thread')
1331
+ self.logger.info("Starting FDR listener thread")
1336
1332
  start_fdr_thread(fdr_type.FDR_CTRL)
1337
1333
 
1338
- sep = self.build_identity['Manifest']['SEP'].get('Info')
1339
- spp = self.build_identity['Info'].get('SystemPartitionPadding')
1340
- opts = RestoreOptions(firmware_preflight_info=self._firmware_preflight_info, sep=sep,
1341
- macos_variant=self.macos_variant,
1342
- build_identity=self.build_identity, restore_boot_args=self.recovery.restore_boot_args,
1343
- spp=spp, restore_behavior=self.build_identity.restore_behavior,
1344
- msp=self.build_identity.minimum_system_partition)
1334
+ sep = self.build_identity["Manifest"]["SEP"].get("Info")
1335
+ spp = self.build_identity["Info"].get("SystemPartitionPadding")
1336
+ opts = RestoreOptions(
1337
+ firmware_preflight_info=self._firmware_preflight_info,
1338
+ sep=sep,
1339
+ macos_variant=self.macos_variant,
1340
+ build_identity=self.build_identity,
1341
+ restore_boot_args=self.recovery.restore_boot_args,
1342
+ spp=spp,
1343
+ restore_behavior=self.build_identity.restore_behavior,
1344
+ msp=self.build_identity.minimum_system_partition,
1345
+ )
1345
1346
 
1346
1347
  # start the restore process
1347
1348
  await self._restored.start_restore(opts)
@@ -1354,17 +1355,17 @@ class Restore(BaseRestore):
1354
1355
  message = await self._restored.recv()
1355
1356
 
1356
1357
  # discover what kind of message has been received
1357
- message_type = message.get('MsgType')
1358
+ message_type = message.get("MsgType")
1358
1359
 
1359
1360
  if message_type in self._handlers:
1360
1361
  try:
1361
1362
  await self._handlers[message_type](message)
1362
1363
  except Exception:
1363
- self.logger.error(traceback.format_exc())
1364
+ self.logger.exception(traceback.format_exc())
1364
1365
  else:
1365
1366
  # there might be some other message types i'm not aware of, but I think
1366
1367
  # at least the "previous error logs" messages usually end up here
1367
- self.logger.debug(f'unhandled message type received: {message}')
1368
+ self.logger.debug(f"unhandled message type received: {message}")
1368
1369
 
1369
1370
  async def update(self):
1370
1371
  await self.recovery.boot_ramdisk()
@@ -1373,24 +1374,24 @@ class Restore(BaseRestore):
1373
1374
  await self.restore_device()
1374
1375
 
1375
1376
  async def _get_service_for_data_request(self, message: dict) -> ServiceConnection:
1376
- data_port = message.get('DataPort')
1377
+ data_port = message.get("DataPort")
1377
1378
  if data_port is None:
1378
1379
  return self._restored.service
1379
- data_type = message['DataType']
1380
- data_port = message['DataPort']
1380
+ data_type = message["DataType"]
1381
+ data_port = message["DataPort"]
1381
1382
 
1382
- self.logger.info(f'Connecting to {data_type} data port ({data_port})')
1383
+ self.logger.info(f"Connecting to {data_type} data port ({data_port})")
1383
1384
 
1384
1385
  while True:
1385
1386
  try:
1386
- service = ServiceConnection.create_using_usbmux(self._restored.udid, data_port, connection_type='USB')
1387
+ service = ServiceConnection.create_using_usbmux(self._restored.udid, data_port, connection_type="USB")
1387
1388
  break
1388
1389
  except ConnectionFailedError:
1389
- self.logger.debug('Retrying connection...')
1390
+ self.logger.debug("Retrying connection...")
1390
1391
 
1391
1392
  if not service:
1392
- raise ConnectionFailedError(f'failed to establish connection to {data_port}')
1393
+ raise ConnectionFailedError(f"failed to establish connection to {data_port}")
1393
1394
 
1394
- self.logger.info(f'Connected to {data_type} data port ({data_port})')
1395
+ self.logger.info(f"Connected to {data_type} data port ({data_port})")
1395
1396
  await service.aio_start()
1396
1397
  return service