pymobiledevice3 5.0.0__py3-none-any.whl → 5.0.2__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 +26 -49
  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 +394 -241
  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 +62 -41
  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 +136 -126
  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 +55 -47
  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 +466 -384
  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 +40 -50
  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 +180 -176
  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 +2 -2
  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 +127 -116
  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.0.dist-info → pymobiledevice3-5.0.2.dist-info}/METADATA +1 -1
  138. pymobiledevice3-5.0.2.dist-info/RECORD +173 -0
  139. pymobiledevice3-5.0.0.dist-info/RECORD +0 -173
  140. {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/WHEEL +0 -0
  141. {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/entry_points.txt +0 -0
  142. {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/licenses/LICENSE +0 -0
  143. {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/top_level.txt +0 -0
@@ -8,9 +8,18 @@ from developer_disk_image.repo import DeveloperDiskImageRepository
8
8
  from packaging.version import Version
9
9
 
10
10
  from pymobiledevice3.common import get_home_folder
11
- from pymobiledevice3.exceptions import AlreadyMountedError, DeveloperDiskImageNotFoundError, \
12
- DeveloperModeIsNotEnabledError, InternalError, MessageNotSupportedError, MissingManifestError, \
13
- NoSuchBuildIdentityError, NotMountedError, PyMobileDevice3Exception, UnsupportedCommandError
11
+ from pymobiledevice3.exceptions import (
12
+ AlreadyMountedError,
13
+ DeveloperDiskImageNotFoundError,
14
+ DeveloperModeIsNotEnabledError,
15
+ InternalError,
16
+ MessageNotSupportedError,
17
+ MissingManifestError,
18
+ NoSuchBuildIdentityError,
19
+ NotMountedError,
20
+ PyMobileDevice3Exception,
21
+ UnsupportedCommandError,
22
+ )
14
23
  from pymobiledevice3.lockdown import LockdownClient
15
24
  from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
16
25
  from pymobiledevice3.restore.tss import TSSRequest
@@ -18,13 +27,13 @@ from pymobiledevice3.services.lockdown_service import LockdownService
18
27
 
19
28
  logger = logging.getLogger(__name__)
20
29
 
21
- LATEST_DDI_BUILD_ID = '17B5045g'
30
+ LATEST_DDI_BUILD_ID = "17B5045g"
22
31
 
23
32
 
24
33
  class MobileImageMounterService(LockdownService):
25
34
  # implemented in /usr/libexec/mobile_storage_proxy
26
- SERVICE_NAME = 'com.apple.mobile.mobile_image_mounter'
27
- RSD_SERVICE_NAME = 'com.apple.mobile.mobile_image_mounter.shim.remote'
35
+ SERVICE_NAME = "com.apple.mobile.mobile_image_mounter"
36
+ RSD_SERVICE_NAME = "com.apple.mobile.mobile_image_mounter.shim.remote"
28
37
  IMAGE_TYPE: Optional[str] = None
29
38
 
30
39
  def __init__(self, lockdown: LockdownServiceProvider):
@@ -40,21 +49,20 @@ class MobileImageMounterService(LockdownService):
40
49
  raise DeveloperModeIsNotEnabledError()
41
50
 
42
51
  def copy_devices(self) -> list[dict]:
43
- """ Copy mounted devices list. """
52
+ """Copy mounted devices list."""
44
53
  try:
45
- return self.service.send_recv_plist({'Command': 'CopyDevices'})['EntryList']
54
+ return self.service.send_recv_plist({"Command": "CopyDevices"})["EntryList"]
46
55
  except KeyError as e:
47
56
  raise MessageNotSupportedError from e
48
57
 
49
58
  def lookup_image(self, image_type: str) -> bytes:
50
- """ Lookup mounted image by its name. """
51
- response = self.service.send_recv_plist({'Command': 'LookupImage',
52
- 'ImageType': image_type})
59
+ """Lookup mounted image by its name."""
60
+ response = self.service.send_recv_plist({"Command": "LookupImage", "ImageType": image_type})
53
61
 
54
- if not response or not response.get('ImagePresent', True):
62
+ if not response or not response.get("ImagePresent", True):
55
63
  raise NotMountedError()
56
64
 
57
- signature = response.get('ImageSignature', [])
65
+ signature = response.get("ImageSignature", [])
58
66
  if isinstance(signature, list):
59
67
  if not signature:
60
68
  raise NotMountedError()
@@ -64,125 +72,128 @@ class MobileImageMounterService(LockdownService):
64
72
  def is_image_mounted(self, image_type: str) -> bool:
65
73
  try:
66
74
  self.lookup_image(image_type)
67
- return True
68
75
  except NotMountedError:
69
76
  return False
77
+ return True
70
78
 
71
79
  def unmount_image(self, mount_path: str) -> None:
72
- """ umount image (Added on iOS 14.0) """
73
- request = {'Command': 'UnmountImage', 'MountPath': mount_path}
80
+ """umount image (Added on iOS 14.0)"""
81
+ request = {"Command": "UnmountImage", "MountPath": mount_path}
74
82
  response = self.service.send_recv_plist(request)
75
83
 
76
- error = response.get('Error')
84
+ error = response.get("Error")
77
85
  if error:
78
- if error == 'UnknownCommand':
86
+ if error == "UnknownCommand":
79
87
  raise UnsupportedCommandError()
80
- elif 'There is no matching entry' in response.get('DetailedError', ''):
88
+ elif "There is no matching entry" in response.get("DetailedError", ""):
81
89
  raise NotMountedError(response)
82
- elif error == 'InternalError':
90
+ elif error == "InternalError":
83
91
  raise InternalError(response)
84
92
  else:
85
93
  raise PyMobileDevice3Exception(response)
86
94
 
87
95
  def mount_image(self, image_type: str, signature: bytes, extras: Optional[dict] = None) -> None:
88
- """ Upload image into device. """
96
+ """Upload image into device."""
89
97
 
90
98
  if self.is_image_mounted(image_type):
91
99
  raise AlreadyMountedError()
92
100
 
93
- request = {'Command': 'MountImage',
94
- 'ImageType': image_type,
95
- 'ImageSignature': signature}
101
+ request = {"Command": "MountImage", "ImageType": image_type, "ImageSignature": signature}
96
102
 
97
103
  if extras is not None:
98
104
  request.update(extras)
99
105
  response = self.service.send_recv_plist(request)
100
106
 
101
- if 'Developer mode is not enabled' in response.get('DetailedError', ''):
107
+ if "Developer mode is not enabled" in response.get("DetailedError", ""):
102
108
  raise DeveloperModeIsNotEnabledError()
103
109
 
104
- status = response.get('Status')
110
+ status = response.get("Status")
105
111
 
106
- if status != 'Complete':
107
- raise PyMobileDevice3Exception(f'command MountImage failed with: {response}')
112
+ if status != "Complete":
113
+ raise PyMobileDevice3Exception(f"command MountImage failed with: {response}")
108
114
 
109
115
  def upload_image(self, image_type: str, image: bytes, signature: bytes) -> None:
110
- """ Upload image into device. """
111
- self.service.send_plist({'Command': 'ReceiveBytes',
112
- 'ImageType': image_type,
113
- 'ImageSize': len(image),
114
- 'ImageSignature': signature})
116
+ """Upload image into device."""
117
+ self.service.send_plist({
118
+ "Command": "ReceiveBytes",
119
+ "ImageType": image_type,
120
+ "ImageSize": len(image),
121
+ "ImageSignature": signature,
122
+ })
115
123
  result = self.service.recv_plist()
116
124
 
117
- status = result.get('Status')
125
+ status = result.get("Status")
118
126
 
119
- if status != 'ReceiveBytesAck':
120
- raise PyMobileDevice3Exception(f'command ReceiveBytes failed with: {result}')
127
+ if status != "ReceiveBytesAck":
128
+ raise PyMobileDevice3Exception(f"command ReceiveBytes failed with: {result}")
121
129
 
122
130
  self.service.sendall(image)
123
131
  result = self.service.recv_plist()
124
132
 
125
- status = result.get('Status')
133
+ status = result.get("Status")
126
134
 
127
- if status != 'Complete':
128
- raise PyMobileDevice3Exception(f'command ReceiveBytes failed to send bytes with: {result}')
135
+ if status != "Complete":
136
+ raise PyMobileDevice3Exception(f"command ReceiveBytes failed to send bytes with: {result}")
129
137
 
130
138
  def query_developer_mode_status(self) -> bool:
131
- response = self.service.send_recv_plist({'Command': 'QueryDeveloperModeStatus'})
139
+ response = self.service.send_recv_plist({"Command": "QueryDeveloperModeStatus"})
132
140
 
133
141
  try:
134
- return response['DeveloperModeStatus']
142
+ return response["DeveloperModeStatus"]
135
143
  except KeyError as e:
136
144
  raise MessageNotSupportedError from e
137
145
 
138
146
  def query_nonce(self, personalized_image_type: Optional[str] = None) -> bytes:
139
- request = {'Command': 'QueryNonce'}
147
+ request = {"Command": "QueryNonce"}
140
148
  if personalized_image_type is not None:
141
- request['PersonalizedImageType'] = personalized_image_type
149
+ request["PersonalizedImageType"] = personalized_image_type
142
150
  response = self.service.send_recv_plist(request)
143
151
  try:
144
- return response['PersonalizationNonce']
152
+ return response["PersonalizationNonce"]
145
153
  except KeyError as e:
146
154
  raise MessageNotSupportedError from e
147
155
 
148
156
  def query_personalization_identifiers(self, image_type: Optional[str] = None) -> dict:
149
- request = {'Command': 'QueryPersonalizationIdentifiers'}
157
+ request = {"Command": "QueryPersonalizationIdentifiers"}
150
158
 
151
159
  if image_type is not None:
152
- request['PersonalizedImageType'] = image_type
160
+ request["PersonalizedImageType"] = image_type
153
161
 
154
162
  response = self.service.send_recv_plist(request)
155
163
 
156
164
  try:
157
- return response['PersonalizationIdentifiers']
165
+ return response["PersonalizationIdentifiers"]
158
166
  except KeyError as e:
159
167
  raise MessageNotSupportedError from e
160
168
 
161
169
  def query_personalization_manifest(self, image_type: str, signature: bytes) -> bytes:
162
170
  response = self.service.send_recv_plist({
163
- 'Command': 'QueryPersonalizationManifest', 'PersonalizedImageType': image_type, 'ImageType': image_type,
164
- 'ImageSignature': signature})
171
+ "Command": "QueryPersonalizationManifest",
172
+ "PersonalizedImageType": image_type,
173
+ "ImageType": image_type,
174
+ "ImageSignature": signature,
175
+ })
165
176
  try:
166
177
  # The response "ImageSignature" is actually an IM4M
167
- return response['ImageSignature']
168
- except KeyError:
169
- raise MissingManifestError()
178
+ return response["ImageSignature"]
179
+ except KeyError as e:
180
+ raise MissingManifestError() from e
170
181
 
171
182
  def roll_personalization_nonce(self) -> None:
172
183
  try:
173
- self.service.send_recv_plist({'Command': 'RollPersonalizationNonce'})
184
+ self.service.send_recv_plist({"Command": "RollPersonalizationNonce"})
174
185
  except ConnectionAbortedError:
175
186
  return
176
187
 
177
188
  def roll_cryptex_nonce(self) -> None:
178
189
  try:
179
- self.service.send_recv_plist({'Command': 'RollCryptexNonce'})
190
+ self.service.send_recv_plist({"Command": "RollCryptexNonce"})
180
191
  except ConnectionAbortedError:
181
192
  return
182
193
 
183
194
 
184
195
  class DeveloperDiskImageMounter(MobileImageMounterService):
185
- IMAGE_TYPE = 'Developer'
196
+ IMAGE_TYPE = "Developer"
186
197
 
187
198
  def mount(self, image: Path, signature: Path) -> None:
188
199
  self.raise_if_cannot_mount()
@@ -193,14 +204,15 @@ class DeveloperDiskImageMounter(MobileImageMounterService):
193
204
  self.mount_image(self.IMAGE_TYPE, signature)
194
205
 
195
206
  def umount(self) -> None:
196
- self.unmount_image('/Developer')
207
+ self.unmount_image("/Developer")
197
208
 
198
209
 
199
210
  class PersonalizedImageMounter(MobileImageMounterService):
200
- IMAGE_TYPE = 'Personalized'
211
+ IMAGE_TYPE = "Personalized"
201
212
 
202
- async def mount(self, image: Path, build_manifest: Path, trust_cache: Path,
203
- info_plist: Optional[dict] = None) -> None:
213
+ async def mount(
214
+ self, image: Path, build_manifest: Path, trust_cache: Path, info_plist: Optional[dict] = None
215
+ ) -> None:
204
216
  self.raise_if_cannot_mount()
205
217
 
206
218
  image = image.read_bytes()
@@ -210,7 +222,7 @@ class PersonalizedImageMounter(MobileImageMounterService):
210
222
  # in case of failure, the service will close the socket, so we'll have to reestablish the connection
211
223
  # and query the manifest from Apple's ticket server instead
212
224
  try:
213
- manifest = self.query_personalization_manifest('DeveloperDiskImage', hashlib.sha384(image).digest())
225
+ manifest = self.query_personalization_manifest("DeveloperDiskImage", hashlib.sha384(image).digest())
214
226
  except MissingManifestError:
215
227
  self.service = self.lockdown.start_lockdown_service(self.service_name)
216
228
  manifest = await self.get_manifest_from_tss(plistlib.loads(build_manifest.read_bytes()))
@@ -219,107 +231,110 @@ class PersonalizedImageMounter(MobileImageMounterService):
219
231
 
220
232
  extras = {}
221
233
  if info_plist is not None:
222
- extras['ImageInfoPlist'] = info_plist
223
- extras['ImageTrustCache'] = trust_cache
234
+ extras["ImageInfoPlist"] = info_plist
235
+ extras["ImageTrustCache"] = trust_cache
224
236
  self.mount_image(self.IMAGE_TYPE, manifest, extras=extras)
225
237
 
226
238
  def umount(self) -> None:
227
- self.unmount_image('/System/Developer')
239
+ self.unmount_image("/System/Developer")
228
240
 
229
241
  async def get_manifest_from_tss(self, build_manifest: dict) -> bytes:
230
242
  request = TSSRequest()
231
243
 
232
244
  personalization_identifiers = self.query_personalization_identifiers()
233
245
  for key, value in personalization_identifiers.items():
234
- if key.startswith('Ap,'):
246
+ if key.startswith("Ap,"):
235
247
  request.update({key: value})
236
248
 
237
- board_id = personalization_identifiers['BoardId']
238
- chip_id = personalization_identifiers['ChipID']
249
+ board_id = personalization_identifiers["BoardId"]
250
+ chip_id = personalization_identifiers["ChipID"]
239
251
 
240
252
  build_identity = None
241
- for tmp_build_identity in build_manifest['BuildIdentities']:
242
- if int(tmp_build_identity['ApBoardID'], 0) == board_id and \
243
- int(tmp_build_identity['ApChipID'], 0) == chip_id:
253
+ for tmp_build_identity in build_manifest["BuildIdentities"]:
254
+ if (
255
+ int(tmp_build_identity["ApBoardID"], 0) == board_id
256
+ and int(tmp_build_identity["ApChipID"], 0) == chip_id
257
+ ):
244
258
  build_identity = tmp_build_identity
245
259
  break
246
260
  else:
247
- raise NoSuchBuildIdentityError(f'Could not find the manifest for board {board_id} and chip {chip_id}')
248
- manifest = build_identity['Manifest']
261
+ raise NoSuchBuildIdentityError(f"Could not find the manifest for board {board_id} and chip {chip_id}")
262
+ manifest = build_identity["Manifest"]
249
263
 
250
264
  parameters = {
251
- 'ApProductionMode': True,
252
- 'ApSecurityDomain': 1,
253
- 'ApSecurityMode': True,
254
- 'ApSupportsImg4': True,
265
+ "ApProductionMode": True,
266
+ "ApSecurityDomain": 1,
267
+ "ApSecurityMode": True,
268
+ "ApSupportsImg4": True,
255
269
  }
256
270
 
257
271
  request.update({
258
- '@ApImg4Ticket': True,
259
- '@BBTicket': True,
260
- 'ApBoardID': board_id,
261
- 'ApChipID': chip_id,
262
- 'ApECID': self.lockdown.ecid,
263
- 'ApNonce': self.query_nonce('DeveloperDiskImage'),
264
- 'ApProductionMode': True,
265
- 'ApSecurityDomain': 1,
266
- 'ApSecurityMode': True,
267
- 'SepNonce': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
268
- 'UID_MODE': False,
272
+ "@ApImg4Ticket": True,
273
+ "@BBTicket": True,
274
+ "ApBoardID": board_id,
275
+ "ApChipID": chip_id,
276
+ "ApECID": self.lockdown.ecid,
277
+ "ApNonce": self.query_nonce("DeveloperDiskImage"),
278
+ "ApProductionMode": True,
279
+ "ApSecurityDomain": 1,
280
+ "ApSecurityMode": True,
281
+ "SepNonce": b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
282
+ "UID_MODE": False,
269
283
  })
270
284
 
271
285
  for key, manifest_entry in manifest.items():
272
- info_dict = manifest_entry.get('Info')
286
+ info_dict = manifest_entry.get("Info")
273
287
  if info_dict is None:
274
288
  continue
275
289
 
276
- if not manifest_entry.get('Trusted', False):
277
- self.logger.debug(f'skipping {key} as it is not trusted')
290
+ if not manifest_entry.get("Trusted", False):
291
+ self.logger.debug(f"skipping {key} as it is not trusted")
278
292
  continue
279
293
 
280
294
  # copy this entry
281
295
  tss_entry = dict(manifest_entry)
282
296
 
283
297
  # remove obsolete Info node
284
- tss_entry.pop('Info')
298
+ tss_entry.pop("Info")
285
299
 
286
300
  # handle RestoreRequestRules
287
- if 'RestoreRequestRules' in manifest['LoadableTrustCache']['Info']:
288
- rules = manifest['LoadableTrustCache']['Info']['RestoreRequestRules']
301
+ if "RestoreRequestRules" in manifest["LoadableTrustCache"]["Info"]:
302
+ rules = manifest["LoadableTrustCache"]["Info"]["RestoreRequestRules"]
289
303
  if rules:
290
- self.logger.debug(f'Applying restore request rules for entry {key}')
304
+ self.logger.debug(f"Applying restore request rules for entry {key}")
291
305
  tss_entry = request.apply_restore_request_rules(tss_entry, parameters, rules)
292
306
 
293
307
  # Make sure we have a Digest key for Trusted items even if empty
294
- if manifest_entry.get('Digest') is None:
295
- tss_entry['Digest'] = b''
308
+ if manifest_entry.get("Digest") is None:
309
+ tss_entry["Digest"] = b""
296
310
 
297
311
  request.update({key: tss_entry})
298
312
 
299
313
  response = await request.send_receive()
300
- return response['ApImg4Ticket']
314
+ return response["ApImg4Ticket"]
301
315
 
302
316
 
303
317
  def auto_mount_developer(
304
- lockdown: LockdownServiceProvider, xcode: Optional[str] = None, version: Optional[str] = None) -> None:
305
- """ auto-detect correct DeveloperDiskImage and mount it """
318
+ lockdown: LockdownServiceProvider, xcode: Optional[str] = None, version: Optional[str] = None
319
+ ) -> None:
320
+ """auto-detect correct DeveloperDiskImage and mount it"""
306
321
  if xcode is None:
307
322
  # avoid "default"-ing this option, because Windows and Linux won't have this path
308
- xcode = Path('/Applications/Xcode.app')
323
+ xcode = Path("/Applications/Xcode.app")
309
324
  if not (xcode.exists()):
310
- xcode = get_home_folder() / 'Xcode.app'
325
+ xcode = get_home_folder() / "Xcode.app"
311
326
  xcode.mkdir(parents=True, exist_ok=True)
312
327
 
313
328
  image_mounter = DeveloperDiskImageMounter(lockdown=lockdown)
314
- if image_mounter.is_image_mounted('Developer'):
329
+ if image_mounter.is_image_mounted("Developer"):
315
330
  raise AlreadyMountedError()
316
331
 
317
332
  if version is None:
318
333
  version = Version(lockdown.product_version)
319
- version = f'{version.major}.{version.minor}'
320
- image_dir = f'{xcode}/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/{version}'
321
- image_path = f'{image_dir}/DeveloperDiskImage.dmg'
322
- signature = f'{image_path}.signature'
334
+ version = f"{version.major}.{version.minor}"
335
+ image_dir = f"{xcode}/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/{version}"
336
+ image_path = f"{image_dir}/DeveloperDiskImage.dmg"
337
+ signature = f"{image_path}.signature"
323
338
  developer_disk_image_dir = Path(image_path).parent
324
339
 
325
340
  image_path = Path(image_path)
@@ -342,15 +357,17 @@ def auto_mount_developer(
342
357
 
343
358
 
344
359
  async def auto_mount_personalized(lockdown: LockdownServiceProvider) -> None:
345
- local_path = get_home_folder() / 'Xcode_iOS_DDI_Personalized'
360
+ local_path = get_home_folder() / "Xcode_iOS_DDI_Personalized"
346
361
  local_path.mkdir(parents=True, exist_ok=True)
347
362
 
348
- image = local_path / 'Image.dmg'
349
- build_manifest = local_path / 'BuildManifest.plist'
350
- trustcache = local_path / 'Image.trustcache'
363
+ image = local_path / "Image.dmg"
364
+ build_manifest = local_path / "BuildManifest.plist"
365
+ trustcache = local_path / "Image.trustcache"
351
366
 
352
- if (not build_manifest.exists() or
353
- plistlib.loads(build_manifest.read_bytes()).get('ProductBuildVersion') != LATEST_DDI_BUILD_ID):
367
+ if (
368
+ not build_manifest.exists()
369
+ or plistlib.loads(build_manifest.read_bytes()).get("ProductBuildVersion") != LATEST_DDI_BUILD_ID
370
+ ):
354
371
  # download the Personalized image from our repository
355
372
  repo = DeveloperDiskImageRepository.create()
356
373
  personalized_image = repo.get_personalized_disk_image()
@@ -358,16 +375,20 @@ async def auto_mount_personalized(lockdown: LockdownServiceProvider) -> None:
358
375
  image.write_bytes(personalized_image.image)
359
376
  build_manifest.write_bytes(personalized_image.build_manifest)
360
377
  trustcache.write_bytes(personalized_image.trustcache)
361
- downloaded_ddi_build_id = plistlib.loads(personalized_image.build_manifest).get('ProductBuildVersion')
378
+ downloaded_ddi_build_id = plistlib.loads(personalized_image.build_manifest).get("ProductBuildVersion")
362
379
  if downloaded_ddi_build_id != LATEST_DDI_BUILD_ID:
363
- logger.warning('Downloaded personalized image has unexpected ProductBuildVersion '
364
- f'{downloaded_ddi_build_id}. Please update pymobiledevice3!')
380
+ logger.warning(
381
+ "Downloaded personalized image has unexpected ProductBuildVersion "
382
+ f"{downloaded_ddi_build_id}. Please update pymobiledevice3!"
383
+ )
365
384
 
366
385
  await PersonalizedImageMounter(lockdown=lockdown).mount(image, build_manifest, trustcache)
367
386
 
368
387
 
369
- async def auto_mount(lockdown: LockdownServiceProvider, xcode: Optional[str] = None, version: Optional[str] = None) -> None:
370
- if Version(lockdown.product_version) < Version('17.0'):
388
+ async def auto_mount(
389
+ lockdown: LockdownServiceProvider, xcode: Optional[str] = None, version: Optional[str] = None
390
+ ) -> None:
391
+ if Version(lockdown.product_version) < Version("17.0"):
371
392
  auto_mount_developer(lockdown, xcode=xcode, version=version)
372
393
  else:
373
394
  await auto_mount_personalized(lockdown)