pymobiledevice3 4.14.6__py3-none-any.whl → 7.0.6__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.
Files changed (164) hide show
  1. misc/plist_sniffer.py +15 -15
  2. misc/remotexpc_sniffer.py +29 -28
  3. misc/understanding_idevice_protocol_layers.md +15 -10
  4. pymobiledevice3/__main__.py +317 -127
  5. pymobiledevice3/_version.py +22 -4
  6. pymobiledevice3/bonjour.py +358 -113
  7. pymobiledevice3/ca.py +253 -16
  8. pymobiledevice3/cli/activation.py +31 -23
  9. pymobiledevice3/cli/afc.py +49 -40
  10. pymobiledevice3/cli/amfi.py +16 -21
  11. pymobiledevice3/cli/apps.py +87 -42
  12. pymobiledevice3/cli/backup.py +160 -90
  13. pymobiledevice3/cli/bonjour.py +44 -40
  14. pymobiledevice3/cli/cli_common.py +204 -198
  15. pymobiledevice3/cli/companion_proxy.py +14 -14
  16. pymobiledevice3/cli/crash.py +105 -56
  17. pymobiledevice3/cli/developer/__init__.py +62 -0
  18. pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
  19. pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
  20. pymobiledevice3/cli/developer/arbitration.py +50 -0
  21. pymobiledevice3/cli/developer/condition.py +33 -0
  22. pymobiledevice3/cli/developer/core_device.py +294 -0
  23. pymobiledevice3/cli/developer/debugserver.py +244 -0
  24. pymobiledevice3/cli/developer/dvt/__init__.py +438 -0
  25. pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
  26. pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
  27. pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
  28. pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
  29. pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
  30. pymobiledevice3/cli/developer/simulate_location.py +51 -0
  31. pymobiledevice3/cli/diagnostics/__init__.py +75 -0
  32. pymobiledevice3/cli/diagnostics/battery.py +47 -0
  33. pymobiledevice3/cli/idam.py +42 -0
  34. pymobiledevice3/cli/lockdown.py +108 -103
  35. pymobiledevice3/cli/mounter.py +158 -99
  36. pymobiledevice3/cli/notification.py +38 -26
  37. pymobiledevice3/cli/pcap.py +45 -24
  38. pymobiledevice3/cli/power_assertion.py +18 -17
  39. pymobiledevice3/cli/processes.py +17 -23
  40. pymobiledevice3/cli/profile.py +165 -109
  41. pymobiledevice3/cli/provision.py +35 -34
  42. pymobiledevice3/cli/remote.py +217 -129
  43. pymobiledevice3/cli/restore.py +159 -143
  44. pymobiledevice3/cli/springboard.py +63 -53
  45. pymobiledevice3/cli/syslog.py +193 -86
  46. pymobiledevice3/cli/usbmux.py +73 -33
  47. pymobiledevice3/cli/version.py +5 -7
  48. pymobiledevice3/cli/webinspector.py +376 -214
  49. pymobiledevice3/common.py +3 -1
  50. pymobiledevice3/exceptions.py +182 -58
  51. pymobiledevice3/irecv.py +52 -53
  52. pymobiledevice3/irecv_devices.py +1489 -464
  53. pymobiledevice3/lockdown.py +473 -275
  54. pymobiledevice3/lockdown_service_provider.py +15 -8
  55. pymobiledevice3/osu/os_utils.py +27 -9
  56. pymobiledevice3/osu/posix_util.py +34 -15
  57. pymobiledevice3/osu/win_util.py +14 -8
  58. pymobiledevice3/pair_records.py +102 -21
  59. pymobiledevice3/remote/common.py +8 -4
  60. pymobiledevice3/remote/core_device/app_service.py +94 -67
  61. pymobiledevice3/remote/core_device/core_device_service.py +17 -14
  62. pymobiledevice3/remote/core_device/device_info.py +5 -5
  63. pymobiledevice3/remote/core_device/diagnostics_service.py +19 -4
  64. pymobiledevice3/remote/core_device/file_service.py +53 -23
  65. pymobiledevice3/remote/remote_service_discovery.py +79 -45
  66. pymobiledevice3/remote/remotexpc.py +73 -44
  67. pymobiledevice3/remote/tunnel_service.py +442 -317
  68. pymobiledevice3/remote/utils.py +14 -13
  69. pymobiledevice3/remote/xpc_message.py +145 -125
  70. pymobiledevice3/resources/dsc_uuid_map.py +19 -19
  71. pymobiledevice3/resources/firmware_notifications.py +20 -16
  72. pymobiledevice3/resources/notifications.txt +144 -0
  73. pymobiledevice3/restore/asr.py +27 -27
  74. pymobiledevice3/restore/base_restore.py +110 -21
  75. pymobiledevice3/restore/consts.py +87 -66
  76. pymobiledevice3/restore/device.py +59 -12
  77. pymobiledevice3/restore/fdr.py +46 -48
  78. pymobiledevice3/restore/ftab.py +19 -19
  79. pymobiledevice3/restore/img4.py +163 -0
  80. pymobiledevice3/restore/mbn.py +587 -0
  81. pymobiledevice3/restore/recovery.py +151 -151
  82. pymobiledevice3/restore/restore.py +562 -544
  83. pymobiledevice3/restore/restore_options.py +131 -110
  84. pymobiledevice3/restore/restored_client.py +51 -31
  85. pymobiledevice3/restore/tss.py +385 -267
  86. pymobiledevice3/service_connection.py +252 -59
  87. pymobiledevice3/services/accessibilityaudit.py +202 -120
  88. pymobiledevice3/services/afc.py +962 -365
  89. pymobiledevice3/services/amfi.py +24 -30
  90. pymobiledevice3/services/companion.py +23 -19
  91. pymobiledevice3/services/crash_reports.py +71 -47
  92. pymobiledevice3/services/debugserver_applist.py +3 -3
  93. pymobiledevice3/services/device_arbitration.py +8 -8
  94. pymobiledevice3/services/device_link.py +101 -79
  95. pymobiledevice3/services/diagnostics.py +973 -967
  96. pymobiledevice3/services/dtfetchsymbols.py +8 -8
  97. pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
  98. pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
  99. pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
  100. pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
  101. pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
  102. pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +466 -384
  103. pymobiledevice3/services/dvt/instruments/device_info.py +20 -11
  104. pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
  105. pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
  106. pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
  107. pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
  108. pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
  109. pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
  110. pymobiledevice3/services/dvt/instruments/process_control.py +35 -10
  111. pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
  112. pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
  113. pymobiledevice3/services/dvt/testmanaged/xcuitest.py +42 -52
  114. pymobiledevice3/services/file_relay.py +10 -10
  115. pymobiledevice3/services/heartbeat.py +9 -8
  116. pymobiledevice3/services/house_arrest.py +16 -15
  117. pymobiledevice3/services/idam.py +20 -0
  118. pymobiledevice3/services/installation_proxy.py +173 -81
  119. pymobiledevice3/services/lockdown_service.py +20 -10
  120. pymobiledevice3/services/misagent.py +22 -19
  121. pymobiledevice3/services/mobile_activation.py +147 -64
  122. pymobiledevice3/services/mobile_config.py +331 -294
  123. pymobiledevice3/services/mobile_image_mounter.py +141 -113
  124. pymobiledevice3/services/mobilebackup2.py +203 -145
  125. pymobiledevice3/services/notification_proxy.py +11 -11
  126. pymobiledevice3/services/os_trace.py +134 -74
  127. pymobiledevice3/services/pcapd.py +314 -302
  128. pymobiledevice3/services/power_assertion.py +10 -9
  129. pymobiledevice3/services/preboard.py +4 -4
  130. pymobiledevice3/services/remote_fetch_symbols.py +21 -14
  131. pymobiledevice3/services/remote_server.py +176 -146
  132. pymobiledevice3/services/restore_service.py +16 -16
  133. pymobiledevice3/services/screenshot.py +15 -12
  134. pymobiledevice3/services/simulate_location.py +7 -7
  135. pymobiledevice3/services/springboard.py +15 -15
  136. pymobiledevice3/services/syslog.py +5 -5
  137. pymobiledevice3/services/web_protocol/alert.py +11 -11
  138. pymobiledevice3/services/web_protocol/automation_session.py +251 -239
  139. pymobiledevice3/services/web_protocol/cdp_screencast.py +46 -37
  140. pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
  141. pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
  142. pymobiledevice3/services/web_protocol/driver.py +114 -111
  143. pymobiledevice3/services/web_protocol/element.py +124 -111
  144. pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
  145. pymobiledevice3/services/web_protocol/selenium_api.py +49 -49
  146. pymobiledevice3/services/web_protocol/session_protocol.py +18 -12
  147. pymobiledevice3/services/web_protocol/switch_to.py +30 -27
  148. pymobiledevice3/services/webinspector.py +189 -155
  149. pymobiledevice3/tcp_forwarder.py +87 -69
  150. pymobiledevice3/tunneld/__init__.py +0 -0
  151. pymobiledevice3/tunneld/api.py +63 -0
  152. pymobiledevice3/tunneld/server.py +603 -0
  153. pymobiledevice3/usbmux.py +198 -147
  154. pymobiledevice3/utils.py +14 -11
  155. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/METADATA +55 -28
  156. pymobiledevice3-7.0.6.dist-info/RECORD +188 -0
  157. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/WHEEL +1 -1
  158. pymobiledevice3/cli/developer.py +0 -1215
  159. pymobiledevice3/cli/diagnostics.py +0 -99
  160. pymobiledevice3/tunneld.py +0 -524
  161. pymobiledevice3-4.14.6.dist-info/RECORD +0 -168
  162. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/entry_points.txt +0 -0
  163. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info/licenses}/LICENSE +0 -0
  164. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  import hashlib
2
3
  import logging
3
4
  import time
@@ -14,9 +15,9 @@ from pymobiledevice3.restore.consts import lpol_file
14
15
  from pymobiledevice3.restore.device import Device
15
16
  from pymobiledevice3.restore.tss import TSSRequest, TSSResponse
16
17
 
17
- RESTORE_VARIANT_ERASE_INSTALL = 'Erase Install (IPSW)'
18
- RESTORE_VARIANT_UPGRADE_INSTALL = 'Upgrade Install (IPSW)'
19
- RESTORE_VARIANT_MACOS_RECOVERY_OS = 'macOS Customer'
18
+ RESTORE_VARIANT_ERASE_INSTALL = "Erase Install (IPSW)"
19
+ RESTORE_VARIANT_UPGRADE_INSTALL = "Upgrade Install (IPSW)"
20
+ RESTORE_VARIANT_MACOS_RECOVERY_OS = "macOS Customer"
20
21
 
21
22
 
22
23
  class Recovery(BaseRestore):
@@ -27,29 +28,29 @@ class Recovery(BaseRestore):
27
28
  self.restore_boot_args = None
28
29
 
29
30
  def reconnect_irecv(self, is_recovery=None):
30
- self.logger.debug('waiting for device to reconnect...')
31
+ self.logger.debug("waiting for device to reconnect...")
31
32
  self.device.irecv = IRecv(ecid=self.device.ecid, is_recovery=is_recovery)
32
- self.logger.debug(f'connected mode: {self.device.irecv.mode}')
33
+ self.logger.debug(f"connected mode: {self.device.irecv.mode}")
33
34
 
34
35
  def get_preboard_manifest(self):
35
36
  overrides = {
36
- '@APTicket': True,
37
- 'ApProductionMode': 0,
38
- 'ApSecurityDomain': 0,
37
+ "@APTicket": True,
38
+ "ApProductionMode": 0,
39
+ "ApSecurityDomain": 0,
39
40
  }
40
41
 
41
42
  parameters = {
42
- 'ApProductionMode': False,
43
- 'ApSecurityMode': False,
44
- 'ApSupportsImg4': True,
43
+ "ApProductionMode": False,
44
+ "ApSecurityMode": False,
45
+ "ApSupportsImg4": True,
45
46
  }
46
47
 
47
- self.build_identity.populate_tss_request_parameters(parameters)
48
+ self.populate_tss_request_from_manifest(parameters)
48
49
 
49
50
  tss = TSSRequest()
50
51
  tss.add_common_tags(parameters, overrides)
51
52
 
52
- parameters['_OnlyFWComponents'] = True
53
+ parameters["_OnlyFWComponents"] = True
53
54
 
54
55
  tss.add_ap_tags(parameters)
55
56
 
@@ -57,29 +58,34 @@ class Recovery(BaseRestore):
57
58
 
58
59
  async def get_tss_response(self) -> TSSResponse:
59
60
  # populate parameters
60
- parameters = dict()
61
+ parameters = {}
61
62
 
62
- parameters['ApECID'] = self.device.ecid
63
+ parameters["ApECID"] = self.device.ecid
63
64
  if self.device.ap_nonce is not None:
64
- parameters['ApNonce'] = self.device.ap_nonce
65
+ parameters["ApNonce"] = self.device.ap_nonce
65
66
 
66
67
  if self.device.sep_nonce is not None:
67
- parameters['ApSepNonce'] = self.device.sep_nonce
68
+ parameters["ApSepNonce"] = self.device.sep_nonce
68
69
 
69
- parameters['ApProductionMode'] = True
70
+ parameters["ApProductionMode"] = True
70
71
 
71
72
  if self.device.is_image4_supported:
72
- parameters['ApSecurityMode'] = True
73
- parameters['ApSupportsImg4'] = True
73
+ parameters["ApSecurityMode"] = True
74
+ parameters["ApSupportsImg4"] = True
74
75
  else:
75
- parameters['ApSupportsImg4'] = False
76
+ parameters["ApSupportsImg4"] = False
76
77
 
77
- self.build_identity.populate_tss_request_parameters(parameters)
78
+ self.populate_tss_request_from_manifest(parameters)
78
79
 
79
80
  tss = TSSRequest()
80
81
  tss.add_common_tags(parameters)
81
82
  tss.add_ap_tags(parameters)
82
83
 
84
+ # TODO: This break updating iPhone 15P Pro. Consider re-adding it once we figure out what went wrong
85
+ # build_manifest_info = self.build_identity['Info']
86
+ # for manifest_property in build_manifest_info.get('RequestManifestProperties', []):
87
+ # tss.add_tags({manifest_property: build_manifest_info[manifest_property]})
88
+
83
89
  # add personalized parameters
84
90
  if self.device.is_image4_supported:
85
91
  tss.add_ap_img4_tags(parameters)
@@ -88,51 +94,52 @@ class Recovery(BaseRestore):
88
94
 
89
95
  # normal mode; request baseband ticket as well
90
96
  if self.device.lockdown is not None:
91
- pinfo = self.device.preflight_info
97
+ pinfo = self.device.firmware_preflight_info
92
98
  if pinfo:
93
- self.logger.debug('adding preflight info')
99
+ self.logger.debug("adding firmware preflight info")
94
100
 
95
- node = pinfo.get('Nonce')
101
+ node = pinfo.get("Nonce")
96
102
  if node is not None:
97
- parameters['BbNonce'] = node
103
+ parameters["BbNonce"] = node
98
104
 
99
- node = pinfo.get('ChipID')
105
+ node = pinfo.get("ChipID")
100
106
  if node is not None:
101
- parameters['BbChipID'] = node
107
+ parameters["BbChipID"] = node
102
108
 
103
- node = pinfo.get('CertID')
109
+ node = pinfo.get("CertID")
104
110
  if node is not None:
105
- parameters['BbGoldCertId'] = node
111
+ parameters["BbGoldCertId"] = node
106
112
 
107
- node = pinfo.get('ChipSerialNo')
113
+ node = pinfo.get("ChipSerialNo")
108
114
  if node is not None:
109
- parameters['BbSNUM'] = node
115
+ parameters["BbSNUM"] = node
110
116
 
111
- tss.add_baseband_tags(parameters)
117
+ # add baseband parameters
118
+ tss.add_baseband_tags(parameters)
112
119
 
113
- euiccchipid = pinfo.get('EUICCChipID')
114
- if euiccchipid:
115
- self.logger.debug('adding EUICCChipID info')
116
- parameters['eUICC,ChipID'] = euiccchipid
120
+ euiccchipid = pinfo.get("EUICCChipID")
121
+ if euiccchipid:
122
+ self.logger.debug("adding EUICCChipID info")
123
+ parameters["eUICC,ChipID"] = euiccchipid
117
124
 
118
- if euiccchipid >= 5:
119
- node = pinfo.get('EUICCCSN')
120
- if node is not None:
121
- parameters['eUICC,EID'] = node
125
+ if euiccchipid >= 5:
126
+ node = pinfo.get("EUICCCSN")
127
+ if node is not None:
128
+ parameters["eUICC,EID"] = node
122
129
 
123
- node = pinfo.get('EUICCCertIdentifier')
124
- if node is not None:
125
- parameters['eUICC,RootKeyIdentifier'] = node
130
+ node = pinfo.get("EUICCCertIdentifier")
131
+ if node is not None:
132
+ parameters["eUICC,RootKeyIdentifier"] = node
126
133
 
127
- node = pinfo.get('EUICCGoldNonce')
128
- if node is not None:
129
- parameters['EUICCGoldNonce'] = node
134
+ node = pinfo.get("EUICCGoldNonce")
135
+ if node is not None:
136
+ parameters["EUICCGoldNonce"] = node
130
137
 
131
- node = pinfo.get('EUICCMainNonce')
132
- if node is not None:
133
- parameters['EUICCMainNonce'] = node
138
+ node = pinfo.get("EUICCMainNonce")
139
+ if node is not None:
140
+ parameters["EUICCMainNonce"] = node
134
141
 
135
- tss.add_vinyl_tags(parameters)
142
+ tss.add_vinyl_tags(parameters)
136
143
 
137
144
  # send request and grab response
138
145
  return await tss.send_receive()
@@ -140,40 +147,40 @@ class Recovery(BaseRestore):
140
147
  def get_local_policy_tss_response(self):
141
148
  # populate parameters
142
149
  parameters = {
143
- 'ApECID': self.device.ecid,
144
- 'Ap,LocalBoot': False,
145
- 'ApProductionMode': True,
150
+ "ApECID": self.device.ecid,
151
+ "Ap,LocalBoot": False,
152
+ "ApProductionMode": True,
146
153
  }
147
154
 
148
155
  if self.device.ap_nonce:
149
- parameters['ApNonce'] = self.device.ap_nonce
156
+ parameters["ApNonce"] = self.device.ap_nonce
150
157
 
151
158
  sep_nonce = self.device.sep_nonce
152
159
 
153
160
  if sep_nonce:
154
- parameters['ApSepNonce'] = sep_nonce
161
+ parameters["ApSepNonce"] = sep_nonce
155
162
 
156
163
  if self.device.is_image4_supported:
157
- parameters['ApSecurityMode'] = True
158
- parameters['ApSupportsImg4'] = True
164
+ parameters["ApSecurityMode"] = True
165
+ parameters["ApSupportsImg4"] = True
159
166
  else:
160
- parameters['ApSupportsImg4'] = False
167
+ parameters["ApSupportsImg4"] = False
161
168
 
162
- self.build_identity.populate_tss_request_parameters(parameters)
169
+ self.populate_tss_request_from_manifest(parameters)
163
170
 
164
171
  # Add Ap,LocalPolicy
165
172
  lpol = {
166
- 'Digest': hashlib.sha384(lpol_file).digest(),
167
- 'Trusted': True,
173
+ "Digest": hashlib.sha384(lpol_file).digest(),
174
+ "Trusted": True,
168
175
  }
169
176
 
170
- parameters['Ap,LocalPolicy'] = lpol
177
+ parameters["Ap,LocalPolicy"] = lpol
171
178
 
172
179
  # Add Ap,NextStageIM4MHash
173
180
  # Get previous TSS ticket
174
181
  ticket = self.tss.ap_img4_ticket
175
182
  # Hash it and add it as Ap,NextStageIM4MHash
176
- parameters['Ap,NextStageIM4MHash'] = hashlib.sha384(ticket).digest()
183
+ parameters["Ap,NextStageIM4MHash"] = hashlib.sha384(ticket).digest()
177
184
 
178
185
  # create basic request
179
186
  request = TSSRequest()
@@ -186,26 +193,26 @@ class Recovery(BaseRestore):
186
193
  def get_recoveryos_root_ticket_tss_response(self):
187
194
  # populate parameters
188
195
  parameters = {
189
- 'ApECID': self.device.ecid,
190
- 'Ap,LocalBoot': False,
191
- 'ApProductionMode': True,
196
+ "ApECID": self.device.ecid,
197
+ "Ap,LocalBoot": False,
198
+ "ApProductionMode": True,
192
199
  }
193
200
 
194
201
  if self.device.ap_nonce:
195
- parameters['ApNonce'] = self.device.ap_nonce
202
+ parameters["ApNonce"] = self.device.ap_nonce
196
203
 
197
204
  sep_nonce = self.device.sep_nonce
198
205
 
199
206
  if sep_nonce:
200
- parameters['ApSepNonce'] = sep_nonce
207
+ parameters["ApSepNonce"] = sep_nonce
201
208
 
202
209
  if self.device.is_image4_supported:
203
- parameters['ApSecurityMode'] = True
204
- parameters['ApSupportsImg4'] = True
210
+ parameters["ApSecurityMode"] = True
211
+ parameters["ApSupportsImg4"] = True
205
212
  else:
206
- parameters['ApSupportsImg4'] = False
213
+ parameters["ApSupportsImg4"] = False
207
214
 
208
- self.build_identity.populate_tss_request_parameters(parameters)
215
+ self.populate_tss_request_from_manifest(parameters)
209
216
 
210
217
  # create basic request
211
218
  # Adds @HostPlatformInfo, @VersionInfo, @UUID
@@ -225,16 +232,19 @@ class Recovery(BaseRestore):
225
232
  return request.send_receive()
226
233
 
227
234
  async def fetch_tss_record(self) -> TSSResponse:
228
- if self.ipsw.build_manifest.build_major > 8:
229
- if self.device.ap_nonce is None:
230
- # the first nonce request with older firmware releases can fail, and it's OK
231
- self.logger.info('NOTE: Unable to get nonce from device')
235
+ if self.ipsw.build_manifest.build_major > 8 and self.device.ap_nonce is None:
236
+ # the first nonce request with older firmware releases can fail, and it's OK
237
+ self.logger.info("NOTE: Unable to get nonce from device")
232
238
 
233
239
  self.tss = await self.get_tss_response()
234
240
 
235
241
  if self.macos_variant:
236
242
  self.tss_localpolicy = self.get_local_policy_tss_response()
237
243
  self.tss_recoveryos_root_ticket = self.get_recoveryos_root_ticket_tss_response()
244
+ else:
245
+ recovery_variant = self.build_identity["Info"].get("RecoveryVariant")
246
+ if recovery_variant is not None:
247
+ self.tss_recoveryos_root_ticket = await self.get_tss_response()
238
248
 
239
249
  return self.tss
240
250
 
@@ -242,13 +252,13 @@ class Recovery(BaseRestore):
242
252
  # Use a specific TSS ticket for the Ap,LocalPolicy component
243
253
  data = None
244
254
  tss = self.tss
245
- if name == 'Ap,LocalPolicy':
255
+ if name == "Ap,LocalPolicy":
246
256
  tss = self.tss_localpolicy
247
257
  # If Ap,LocalPolicy => Inject an empty policy
248
258
  data = lpol_file
249
259
 
250
- data = self.build_identity.get_component(name, tss=tss, data=data).personalized_data
251
- self.logger.info(f'Sending {name} ({len(data)} bytes)...')
260
+ data = self.get_personalized_data(name, data=data, tss=tss)
261
+ self.logger.info(f"Sending {name} ({len(data)} bytes)...")
252
262
  self.device.irecv.send_buffer(data)
253
263
 
254
264
  def send_component_and_command(self, name, command):
@@ -256,114 +266,110 @@ class Recovery(BaseRestore):
256
266
  self.device.irecv.send_command(command)
257
267
 
258
268
  def send_ibec(self):
259
- component = 'iBEC'
269
+ component = "iBEC"
260
270
  self.send_component(component)
261
- self.device.irecv.send_command('go', b_request=1)
271
+ self.device.irecv.send_command("go", b_request=1)
262
272
  self.device.irecv.ctrl_transfer(0x21, 1)
263
273
 
264
274
  def send_applelogo(self, allow_missing=True):
265
- component = 'RestoreLogo'
275
+ component = "RestoreLogo"
266
276
 
267
277
  if not self.build_identity.has_component(component):
268
278
  if allow_missing:
269
- logging.warning(f'build_identity has no {component}')
279
+ logging.warning(f"build_identity has no {component}")
270
280
  return
271
281
  else:
272
- raise PyMobileDevice3Exception(f'missing component: {component}')
282
+ raise PyMobileDevice3Exception(f"missing component: {component}")
273
283
 
274
284
  self.send_component(component)
275
- self.device.irecv.send_command('setpicture 4')
276
- self.device.irecv.send_command('bgcolor 0 0 0')
285
+ self.device.irecv.send_command("setpicture 4")
286
+ self.device.irecv.send_command("bgcolor 0 0 0")
277
287
 
278
288
  def send_loaded_by_iboot(self):
279
- manifest = self.build_identity['Manifest']
289
+ manifest = self.build_identity["Manifest"]
280
290
  for key, node in manifest.items():
281
- iboot = node['Info'].get('IsLoadedByiBoot', False)
282
- iboot_stg1 = node['Info'].get('IsLoadedByiBootStage1', False)
291
+ iboot = node["Info"].get("IsLoadedByiBoot", False)
292
+ iboot_stg1 = node["Info"].get("IsLoadedByiBootStage1", False)
283
293
 
284
294
  assert isinstance(iboot, bool)
285
295
  assert isinstance(iboot_stg1, bool)
286
296
 
287
297
  if iboot and not iboot_stg1:
288
- self.logger.debug(f'{key} is loaded by iBoot')
289
- self.send_component_and_command(key, 'firmware')
298
+ self.logger.debug(f"{key} is loaded by iBoot")
299
+ self.send_component_and_command(key, "firmware")
290
300
 
291
301
  def send_iboot_stage1_components(self):
292
- manifest = self.build_identity['Manifest']
302
+ manifest = self.build_identity["Manifest"]
293
303
  for key, node in manifest.items():
294
- iboot = node['Info'].get('IsLoadedByiBoot', False)
295
- iboot_stg1 = node['Info'].get('IsLoadedByiBootStage1', False)
304
+ iboot = node["Info"].get("IsLoadedByiBoot", False)
305
+ iboot_stg1 = node["Info"].get("IsLoadedByiBootStage1", False)
296
306
 
297
307
  assert isinstance(iboot, bool)
298
308
  assert isinstance(iboot_stg1, bool)
299
309
 
300
310
  if iboot and iboot_stg1:
301
- self.logger.debug(f'{key} is loaded by iBoot Stage 1')
302
- self.send_component_and_command(key, 'firmware')
311
+ self.logger.debug(f"{key} is loaded by iBoot Stage 1")
312
+ self.send_component_and_command(key, "firmware")
303
313
 
304
314
  def send_ramdisk(self):
305
- component = 'RestoreRamDisk'
306
- ramdisk_size = self.device.irecv.getenv('ramdisk-size')
307
- self.logger.info(f'ramdisk-size: {ramdisk_size}')
315
+ component = "RestoreRamDisk"
316
+ ramdisk_size = self.device.irecv.getenv("ramdisk-size")
317
+ self.logger.info(f"ramdisk-size: {ramdisk_size}")
308
318
 
309
319
  self.send_component(component)
310
- ramdisk_delay = self.device.irecv.getenv('ramdisk-delay')
311
- self.logger.info(f'ramdisk-delay: {ramdisk_delay}')
320
+ ramdisk_delay = self.device.irecv.getenv("ramdisk-delay")
321
+ self.logger.info(f"ramdisk-delay: {ramdisk_delay}")
312
322
 
313
- self.device.irecv.send_command('ramdisk')
323
+ self.device.irecv.send_command("ramdisk")
314
324
 
315
325
  time.sleep(2)
316
326
 
317
327
  def send_kernelcache(self):
318
- component = 'RestoreKernelCache'
328
+ component = "RestoreKernelCache"
319
329
 
320
330
  self.send_component(component)
321
- try:
331
+ with contextlib.suppress(USBError):
322
332
  self.device.irecv.ctrl_transfer(0x21, 1)
323
- except USBError:
324
- pass
325
333
 
326
334
  if self.restore_boot_args:
327
- self.device.irecv.send_command(f'setenv boot-args {self.restore_boot_args}')
335
+ self.device.irecv.send_command(f"setenv boot-args {self.restore_boot_args}")
328
336
 
329
- try:
330
- self.device.irecv.send_command('bootx', b_request=1)
331
- except USBError:
332
- pass
337
+ with contextlib.suppress(USBError):
338
+ self.device.irecv.send_command("bootx", b_request=1)
333
339
 
334
340
  def set_autoboot(self, enable: bool):
335
341
  self.device.irecv.set_autoboot(enable)
336
342
 
337
343
  def enter_restore(self):
338
- if self.ipsw.build_manifest.build_major >= 8:
339
- self.restore_boot_args = 'rd=md0 nand-enable-reformat=1 -progress'
340
- elif self.macos_variant:
341
- self.restore_boot_args = 'rd=md0 nand-enable-reformat=1 -progress -restore'
344
+ if self.macos_variant:
345
+ self.restore_boot_args = "rd=md0 nand-enable-reformat=1 -progress -restore"
346
+ elif self.ipsw.build_manifest.build_major >= 8:
347
+ self.restore_boot_args = "rd=md0 nand-enable-reformat=1 -progress"
342
348
 
343
349
  # upload data to make device boot restore mode
344
350
 
345
351
  # Recovery Mode Environment:
346
352
  build_version = None
347
353
  while not build_version:
348
- self.logger.debug('build-version not yet supported. reconnecting...')
354
+ self.logger.debug("build-version not yet supported. reconnecting...")
349
355
  time.sleep(1)
350
356
 
351
357
  # sometimes we manage to connect before iBEC actually started running
352
- build_version = self.device.irecv.getenv('build-version')
358
+ build_version = self.device.irecv.getenv("build-version")
353
359
  self.reconnect_irecv()
354
360
 
355
- self.logger.info(f'iBoot build-version={build_version}')
361
+ self.logger.info(f"iBoot build-version={build_version}")
356
362
 
357
- build_style = self.device.irecv.getenv('build-style')
358
- self.logger.info(f'iBoot build-style={build_style}')
363
+ build_style = self.device.irecv.getenv("build-style")
364
+ self.logger.info(f"iBoot build-style={build_style}")
359
365
 
360
- radio_error = self.device.irecv.getenv('radio-error')
366
+ radio_error = self.device.irecv.getenv("radio-error")
361
367
  if radio_error:
362
368
  radio_error = int(radio_error)
363
- self.logger.info(f'radio-error: {radio_error}')
364
- radio_error_string = self.device.irecv.getenv('radio-error-string')
369
+ self.logger.info(f"radio-error: {radio_error}")
370
+ radio_error_string = self.device.irecv.getenv("radio-error-string")
365
371
  if radio_error_string:
366
- self.logger.info(f'radio-error-string: {radio_error_string}')
372
+ self.logger.info(f"radio-error-string: {radio_error_string}")
367
373
 
368
374
  self.set_autoboot(False)
369
375
 
@@ -377,23 +383,21 @@ class Recovery(BaseRestore):
377
383
  self.send_ramdisk()
378
384
 
379
385
  # send devicetree and load it
380
- self.send_component_and_command('RestoreDeviceTree', 'devicetree')
386
+ self.send_component_and_command("RestoreDeviceTree", "devicetree")
381
387
 
382
- if self.build_identity.has_component('RestoreSEP'):
388
+ if self.build_identity.has_component("RestoreSEP"):
383
389
  # attempt to send rsepfirmware and load it, otherwise continue
384
- try:
385
- self.send_component_and_command('RestoreSEP', 'rsepfirmware')
386
- except USBError:
387
- pass
390
+ with contextlib.suppress(USBError):
391
+ self.send_component_and_command("RestoreSEP", "rsepfirmware")
388
392
 
389
393
  self.send_kernelcache()
390
394
 
391
395
  async def dfu_enter_recovery(self) -> None:
392
- self.send_component('iBSS')
396
+ self.send_component("iBSS")
393
397
  self.reconnect_irecv()
394
398
 
395
- if 'SRTG' in self.device.irecv._device_info:
396
- raise PyMobileDevice3Exception('Device failed to enter recovery')
399
+ if "SRTG" in self.device.irecv._device_info:
400
+ raise PyMobileDevice3Exception("Device failed to enter recovery")
397
401
 
398
402
  if self.build_identity.build_manifest.build_major > 8:
399
403
  old_nonce = self.device.irecv.ap_nonce
@@ -411,43 +415,41 @@ class Recovery(BaseRestore):
411
415
  # Now, before sending iBEC, we must send necessary firmwares on new versions.
412
416
  if self.macos_variant:
413
417
  # Without this empty policy file & its special signature, iBEC won't start.
414
- self.send_component_and_command('Ap,LocalPolicy', 'lpolrestore')
418
+ self.send_component_and_command("Ap,LocalPolicy", "lpolrestore")
415
419
  self.send_iboot_stage1_components()
416
420
  self.device.irecv.set_autoboot(False)
417
- self.device.irecv.send_command('setenvnp boot-args rd=md0 nand-enable-reformat=1 -progress -restore')
421
+ self.device.irecv.send_command("setenvnp boot-args rd=md0 nand-enable-reformat=1 -progress -restore")
418
422
  self.send_applelogo(allow_missing=False)
419
423
 
420
424
  mode = self.device.irecv.mode
421
425
  # send iBEC
422
- self.send_component('iBEC')
426
+ self.send_component("iBEC")
423
427
 
424
428
  if self.device.irecv and mode.is_recovery:
425
429
  time.sleep(1)
426
- self.device.irecv.send_command('go', b_request=1)
430
+ self.device.irecv.send_command("go", b_request=1)
427
431
 
428
432
  if self.build_identity.build_manifest.build_major < 20:
429
- try:
433
+ with contextlib.suppress(USBError):
430
434
  self.device.irecv.ctrl_transfer(0x21, 1, timeout=5000)
431
- except USBError:
432
- pass
433
435
 
434
- self.logger.debug('Waiting for device to disconnect...')
436
+ self.logger.debug("Waiting for device to disconnect...")
435
437
  time.sleep(10)
436
438
 
437
- self.logger.debug('Waiting for device to reconnect in recovery mode...')
439
+ self.logger.debug("Waiting for device to reconnect in recovery mode...")
438
440
  self.reconnect_irecv(is_recovery=True)
439
441
 
440
442
  async def boot_ramdisk(self) -> None:
441
443
  if self.tss is None:
442
- self.logger.info('fetching TSS record')
444
+ self.logger.info("fetching TSS record")
443
445
  await self.fetch_tss_record()
444
446
 
445
447
  if self.device.lockdown:
446
448
  # normal mode
447
- self.logger.info('going into Recovery')
449
+ self.logger.info("going into Recovery")
448
450
 
449
- # in case lockdown has disconnected while waiting for a ticket
450
- self.device.lockdown = create_using_usbmux(serial=self.device.lockdown.udid, connection_type='USB')
451
+ # In case lockdown has disconnected while waiting for a ticket
452
+ self.device.lockdown = create_using_usbmux(serial=self.device.lockdown.udid, connection_type="USB")
451
453
  self.device.lockdown.enter_recovery()
452
454
 
453
455
  self.device.lockdown = None
@@ -460,14 +462,12 @@ class Recovery(BaseRestore):
460
462
 
461
463
  elif self.device.irecv.mode.is_recovery:
462
464
  # now we load the iBEC
463
- try:
465
+ with contextlib.suppress(USBError):
464
466
  self.send_ibec()
465
- except USBError:
466
- pass
467
467
 
468
468
  self.reconnect_irecv(is_recovery=True)
469
469
 
470
- self.logger.info('device booted into recovery')
470
+ self.logger.info("device booted into recovery")
471
471
 
472
472
  # now finally do the magic to put the device into restore mode
473
473
  self.enter_restore()