pymobiledevice3 5.0.1__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 +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 +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.1.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.1.dist-info/RECORD +0 -173
  140. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/WHEEL +0 -0
  141. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/entry_points.txt +0 -0
  142. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/licenses/LICENSE +0 -0
  143. {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.2.dist-info}/top_level.txt +0 -0
@@ -6,8 +6,14 @@ from contextlib import contextmanager, suppress
6
6
  from datetime import datetime
7
7
  from pathlib import Path
8
8
 
9
- from pymobiledevice3.exceptions import AfcException, AfcFileNotFoundError, ConnectionTerminatedError, LockdownError, \
10
- MissingValueError, PyMobileDevice3Exception
9
+ from pymobiledevice3.exceptions import (
10
+ AfcException,
11
+ AfcFileNotFoundError,
12
+ ConnectionTerminatedError,
13
+ LockdownError,
14
+ MissingValueError,
15
+ PyMobileDevice3Exception,
16
+ )
11
17
  from pymobiledevice3.lockdown import LockdownClient
12
18
  from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
13
19
  from pymobiledevice3.services.afc import AFC_LOCK_EX, AFC_LOCK_UN, AfcService, afc_error_t
@@ -19,19 +25,27 @@ from pymobiledevice3.services.springboard import SpringBoardServicesService
19
25
 
20
26
  SUPPORTED_VERSIONS = [2.0, 2.1]
21
27
  ITUNES_FILES = [
22
- 'ApertureAlbumPrefs', 'IC-Info.sidb', 'IC-Info.sidv', 'PhotosFolderAlbums', 'PhotosFolderName',
23
- 'PhotosFolderPrefs', 'VoiceMemos.plist', 'iPhotoAlbumPrefs', 'iTunesApplicationIDs', 'iTunesPrefs',
24
- 'iTunesPrefs.plist'
28
+ "ApertureAlbumPrefs",
29
+ "IC-Info.sidb",
30
+ "IC-Info.sidv",
31
+ "PhotosFolderAlbums",
32
+ "PhotosFolderName",
33
+ "PhotosFolderPrefs",
34
+ "VoiceMemos.plist",
35
+ "iPhotoAlbumPrefs",
36
+ "iTunesApplicationIDs",
37
+ "iTunesPrefs",
38
+ "iTunesPrefs.plist",
25
39
  ]
26
- NP_SYNC_WILL_START = 'com.apple.itunes-mobdev.syncWillStart'
27
- NP_SYNC_DID_START = 'com.apple.itunes-mobdev.syncDidStart'
28
- NP_SYNC_LOCK_REQUEST = 'com.apple.itunes-mobdev.syncLockRequest'
29
- NP_SYNC_DID_FINISH = 'com.apple.itunes-mobdev.syncDidFinish'
40
+ NP_SYNC_WILL_START = "com.apple.itunes-mobdev.syncWillStart"
41
+ NP_SYNC_DID_START = "com.apple.itunes-mobdev.syncDidStart"
42
+ NP_SYNC_LOCK_REQUEST = "com.apple.itunes-mobdev.syncLockRequest"
43
+ NP_SYNC_DID_FINISH = "com.apple.itunes-mobdev.syncDidFinish"
30
44
 
31
45
 
32
46
  class Mobilebackup2Service(LockdownService):
33
- SERVICE_NAME = 'com.apple.mobilebackup2'
34
- RSD_SERVICE_NAME = 'com.apple.mobilebackup2.shim.remote'
47
+ SERVICE_NAME = "com.apple.mobilebackup2"
48
+ RSD_SERVICE_NAME = "com.apple.mobilebackup2.shim.remote"
35
49
 
36
50
  def __init__(self, lockdown: LockdownServiceProvider) -> None:
37
51
  if isinstance(lockdown, LockdownClient):
@@ -42,11 +56,11 @@ class Mobilebackup2Service(LockdownService):
42
56
  @property
43
57
  def will_encrypt(self) -> bool:
44
58
  try:
45
- return self.lockdown.get_value('com.apple.mobile.backup', 'WillEncrypt')
59
+ return self.lockdown.get_value("com.apple.mobile.backup", "WillEncrypt")
46
60
  except LockdownError:
47
61
  return False
48
62
 
49
- def backup(self, full: bool = True, backup_directory: str = '.', progress_callback=lambda x: None) -> None:
63
+ def backup(self, full: bool = True, backup_directory: str = ".", progress_callback=lambda x: None) -> None:
50
64
  """
51
65
  Backup a device.
52
66
  :param full: Whether to do a full backup. If full is True, any previous backup attempts will be discarded.
@@ -58,42 +72,58 @@ class Mobilebackup2Service(LockdownService):
58
72
  device_directory = backup_directory / self.lockdown.udid
59
73
  device_directory.mkdir(exist_ok=True, mode=0o755, parents=True)
60
74
 
61
- with self.device_link(backup_directory) as dl, \
62
- NotificationProxyService(self.lockdown) as notification_proxy, \
63
- AfcService(self.lockdown) as afc:
64
- with self._backup_lock(afc, notification_proxy):
65
- # Initialize Info.plist
66
- info_plist = self.init_mobile_backup_factory_info(afc)
67
- with open(device_directory / 'Info.plist', 'wb') as fd:
68
- plistlib.dump(info_plist, fd)
75
+ with (
76
+ self.device_link(backup_directory) as dl,
77
+ NotificationProxyService(self.lockdown) as notification_proxy,
78
+ AfcService(self.lockdown) as afc,
79
+ self._backup_lock(afc, notification_proxy),
80
+ ):
81
+ # Initialize Info.plist
82
+ info_plist = self.init_mobile_backup_factory_info(afc)
83
+ with open(device_directory / "Info.plist", "wb") as fd:
84
+ plistlib.dump(info_plist, fd)
69
85
 
70
- # Initialize Status.plist file if doesn't exist.
71
- status_path = device_directory / 'Status.plist'
72
- current_date = datetime.now()
73
- current_date = current_date.replace(tzinfo=None)
74
- if full or not status_path.exists():
75
- with open(device_directory / 'Status.plist', 'wb') as fd:
76
- plistlib.dump({
77
- 'BackupState': 'new',
78
- 'Date': current_date,
79
- 'IsFullBackup': full,
80
- 'Version': '3.3',
81
- 'SnapshotState': 'finished',
82
- 'UUID': str(uuid.uuid4()).upper(),
83
- }, fd, fmt=plistlib.FMT_BINARY)
86
+ # Initialize Status.plist file if doesn't exist.
87
+ status_path = device_directory / "Status.plist"
88
+ current_date = datetime.now()
89
+ current_date = current_date.replace(tzinfo=None)
90
+ if full or not status_path.exists():
91
+ with open(device_directory / "Status.plist", "wb") as fd:
92
+ plistlib.dump(
93
+ {
94
+ "BackupState": "new",
95
+ "Date": current_date,
96
+ "IsFullBackup": full,
97
+ "Version": "3.3",
98
+ "SnapshotState": "finished",
99
+ "UUID": str(uuid.uuid4()).upper(),
100
+ },
101
+ fd,
102
+ fmt=plistlib.FMT_BINARY,
103
+ )
84
104
 
85
- # Create Manifest.plist if doesn't exist.
86
- manifest_path = device_directory / 'Manifest.plist'
87
- if full:
88
- manifest_path.unlink(missing_ok=True)
89
- (device_directory / 'Manifest.plist').touch()
105
+ # Create Manifest.plist if doesn't exist.
106
+ manifest_path = device_directory / "Manifest.plist"
107
+ if full:
108
+ manifest_path.unlink(missing_ok=True)
109
+ (device_directory / "Manifest.plist").touch()
90
110
 
91
- dl.send_process_message({'MessageName': 'Backup', 'TargetIdentifier': self.lockdown.udid})
92
- dl.dl_loop(progress_callback)
111
+ dl.send_process_message({"MessageName": "Backup", "TargetIdentifier": self.lockdown.udid})
112
+ dl.dl_loop(progress_callback)
93
113
 
94
- def restore(self, backup_directory='.', system: bool = False, reboot: bool = True, copy: bool = True,
95
- settings: bool = True, remove: bool = False, password: str = '', source: str = '',
96
- progress_callback=lambda x: None, skip_apps: bool = False):
114
+ def restore(
115
+ self,
116
+ backup_directory=".",
117
+ system: bool = False,
118
+ reboot: bool = True,
119
+ copy: bool = True,
120
+ settings: bool = True,
121
+ remove: bool = False,
122
+ password: str = "",
123
+ source: str = "",
124
+ progress_callback=lambda x: None,
125
+ skip_apps: bool = False,
126
+ ):
97
127
  """
98
128
  Restore a previous backup to the device.
99
129
  :param backup_directory: Path of the backup directory.
@@ -112,46 +142,48 @@ class Mobilebackup2Service(LockdownService):
112
142
  source = source if source else self.lockdown.udid
113
143
  self._assert_backup_exists(backup_directory, source)
114
144
 
115
- with self.device_link(backup_directory) as dl, \
116
- NotificationProxyService(self.lockdown) as notification_proxy, \
117
- AfcService(self.lockdown) as afc:
118
- with self._backup_lock(afc, notification_proxy):
119
- manifest_plist_path = backup_directory / source / 'Manifest.plist'
120
- with open(manifest_plist_path, 'rb') as fd:
121
- manifest = plistlib.load(fd)
122
- is_encrypted = manifest.get('IsEncrypted', False)
123
- options = {
124
- 'RestoreShouldReboot': reboot,
125
- 'RestoreDontCopyBackup': not copy,
126
- 'RestorePreserveSettings': settings,
127
- 'RestoreSystemFiles': system,
128
- 'RemoveItemsNotRestored': remove,
129
- }
130
- if is_encrypted:
131
- if password:
132
- options['Password'] = password
133
- else:
134
- self.logger.error('Backup is encrypted, please supply password.')
135
- return
136
- dl.send_process_message({
137
- 'MessageName': 'Restore',
138
- 'TargetIdentifier': self.lockdown.udid,
139
- 'SourceIdentifier': source,
140
- 'Options': options,
141
- })
145
+ with (
146
+ self.device_link(backup_directory) as dl,
147
+ NotificationProxyService(self.lockdown) as notification_proxy,
148
+ AfcService(self.lockdown) as afc,
149
+ self._backup_lock(afc, notification_proxy),
150
+ ):
151
+ manifest_plist_path = backup_directory / source / "Manifest.plist"
152
+ with open(manifest_plist_path, "rb") as fd:
153
+ manifest = plistlib.load(fd)
154
+ is_encrypted = manifest.get("IsEncrypted", False)
155
+ options = {
156
+ "RestoreShouldReboot": reboot,
157
+ "RestoreDontCopyBackup": not copy,
158
+ "RestorePreserveSettings": settings,
159
+ "RestoreSystemFiles": system,
160
+ "RemoveItemsNotRestored": remove,
161
+ }
162
+ if is_encrypted:
163
+ if password:
164
+ options["Password"] = password
165
+ else:
166
+ self.logger.error("Backup is encrypted, please supply password.")
167
+ return
168
+ dl.send_process_message({
169
+ "MessageName": "Restore",
170
+ "TargetIdentifier": self.lockdown.udid,
171
+ "SourceIdentifier": source,
172
+ "Options": options,
173
+ })
142
174
 
143
- if not skip_apps:
144
- # Write /iTunesRestore/RestoreApplications.plist so that the device will start
145
- # restoring applications once the rest of the restore process is finished
146
- info_plist_path = backup_directory / source / 'Info.plist'
147
- applications = plistlib.loads(info_plist_path.read_bytes()).get('Applications')
148
- if applications is not None:
149
- afc.makedirs('/iTunesRestore')
150
- afc.set_file_contents('/iTunesRestore/RestoreApplications.plist', plistlib.dumps(applications))
175
+ if not skip_apps:
176
+ # Write /iTunesRestore/RestoreApplications.plist so that the device will start
177
+ # restoring applications once the rest of the restore process is finished
178
+ info_plist_path = backup_directory / source / "Info.plist"
179
+ applications = plistlib.loads(info_plist_path.read_bytes()).get("Applications")
180
+ if applications is not None:
181
+ afc.makedirs("/iTunesRestore")
182
+ afc.set_file_contents("/iTunesRestore/RestoreApplications.plist", plistlib.dumps(applications))
151
183
 
152
- dl.dl_loop(progress_callback)
184
+ dl.dl_loop(progress_callback)
153
185
 
154
- def info(self, backup_directory='.', source: str = '') -> str:
186
+ def info(self, backup_directory=".", source: str = "") -> str:
155
187
  """
156
188
  Get information about a backup.
157
189
  :param backup_directory: Path of the backup directory.
@@ -161,14 +193,14 @@ class Mobilebackup2Service(LockdownService):
161
193
  backup_dir = Path(backup_directory)
162
194
  self._assert_backup_exists(backup_dir, source if source else self.lockdown.udid)
163
195
  with self.device_link(backup_dir) as dl:
164
- message = {'MessageName': 'Info', 'TargetIdentifier': self.lockdown.udid}
196
+ message = {"MessageName": "Info", "TargetIdentifier": self.lockdown.udid}
165
197
  if source:
166
- message['SourceIdentifier'] = source
198
+ message["SourceIdentifier"] = source
167
199
  dl.send_process_message(message)
168
200
  result = dl.dl_loop()
169
201
  return result
170
202
 
171
- def list(self, backup_directory='.', source: str = '') -> str:
203
+ def list(self, backup_directory=".", source: str = "") -> str:
172
204
  """
173
205
  List the files in the last backup.
174
206
  :param backup_directory: Path of the backup directory.
@@ -180,12 +212,14 @@ class Mobilebackup2Service(LockdownService):
180
212
  self._assert_backup_exists(backup_dir, source)
181
213
  with self.device_link(backup_dir) as dl:
182
214
  dl.send_process_message({
183
- 'MessageName': 'List', 'TargetIdentifier': self.lockdown.udid, 'SourceIdentifier': source,
215
+ "MessageName": "List",
216
+ "TargetIdentifier": self.lockdown.udid,
217
+ "SourceIdentifier": source,
184
218
  })
185
219
  result = dl.dl_loop()
186
220
  return result
187
221
 
188
- def unback(self, backup_directory='.', password: str = '', source: str = '') -> None:
222
+ def unback(self, backup_directory=".", password: str = "", source: str = "") -> None:
189
223
  """
190
224
  Unpack a complete backup to its device hierarchy.
191
225
  :param backup_directory: Path of the backup directory.
@@ -195,16 +229,17 @@ class Mobilebackup2Service(LockdownService):
195
229
  backup_dir = Path(backup_directory)
196
230
  self._assert_backup_exists(backup_dir, source if source else self.lockdown.udid)
197
231
  with self.device_link(backup_dir) as dl:
198
- message = {'MessageName': 'Unback', 'TargetIdentifier': self.lockdown.udid}
232
+ message = {"MessageName": "Unback", "TargetIdentifier": self.lockdown.udid}
199
233
  if source:
200
- message['SourceIdentifier'] = source
234
+ message["SourceIdentifier"] = source
201
235
  if password:
202
- message['Password'] = password
236
+ message["Password"] = password
203
237
  dl.send_process_message(message)
204
238
  dl.dl_loop()
205
239
 
206
- def extract(self, domain_name: str, relative_path: str, backup_directory='.', password: str = '',
207
- source: str = '') -> None:
240
+ def extract(
241
+ self, domain_name: str, relative_path: str, backup_directory=".", password: str = "", source: str = ""
242
+ ) -> None:
208
243
  """
209
244
  Extract a file from a previous backup.
210
245
  :param domain_name: File's domain name, e.g., SystemPreferencesDomain or HomeDomain.
@@ -217,17 +252,19 @@ class Mobilebackup2Service(LockdownService):
217
252
  self._assert_backup_exists(backup_dir, source if source else self.lockdown.udid)
218
253
  with self.device_link(backup_dir) as dl:
219
254
  message = {
220
- 'MessageName': 'Extract', 'TargetIdentifier': self.lockdown.udid, 'DomainName': domain_name,
221
- 'RelativePath': relative_path
255
+ "MessageName": "Extract",
256
+ "TargetIdentifier": self.lockdown.udid,
257
+ "DomainName": domain_name,
258
+ "RelativePath": relative_path,
222
259
  }
223
260
  if source:
224
- message['SourceIdentifier'] = source
261
+ message["SourceIdentifier"] = source
225
262
  if password:
226
- message['Password'] = password
263
+ message["Password"] = password
227
264
  dl.send_process_message(message)
228
265
  dl.dl_loop()
229
266
 
230
- def change_password(self, backup_directory='.', old: str = '', new: str = '') -> None:
267
+ def change_password(self, backup_directory=".", old: str = "", new: str = "") -> None:
231
268
  """
232
269
  Change backup password.
233
270
  :param backup_directory: Backups directory.
@@ -235,22 +272,21 @@ class Mobilebackup2Service(LockdownService):
235
272
  :param new: New password. Omit when disabling backup encryption.
236
273
  """
237
274
  with self.device_link(Path(backup_directory)) as dl:
238
- message = {'MessageName': 'ChangePassword', 'TargetIdentifier': self.lockdown.udid}
275
+ message = {"MessageName": "ChangePassword", "TargetIdentifier": self.lockdown.udid}
239
276
  if old:
240
- message['OldPassword'] = old
277
+ message["OldPassword"] = old
241
278
  if new:
242
- message['NewPassword'] = new
279
+ message["NewPassword"] = new
243
280
  dl.send_process_message(message)
244
281
  dl.dl_loop()
245
282
 
246
- def erase_device(self, backup_directory='.') -> None:
283
+ def erase_device(self, backup_directory=".") -> None:
247
284
  """
248
285
  Erase the device.
249
286
  """
250
- with suppress(ConnectionTerminatedError):
251
- with self.device_link(Path(backup_directory)) as dl:
252
- dl.send_process_message({'MessageName': 'EraseDevice', 'TargetIdentifier': self.lockdown.udid})
253
- dl.dl_loop()
287
+ with suppress(ConnectionTerminatedError), self.device_link(Path(backup_directory)) as dl:
288
+ dl.send_process_message({"MessageName": "EraseDevice", "TargetIdentifier": self.lockdown.udid})
289
+ dl.dl_loop()
254
290
 
255
291
  def version_exchange(self, dl: DeviceLink, local_versions=None) -> None:
256
292
  """
@@ -261,87 +297,89 @@ class Mobilebackup2Service(LockdownService):
261
297
  if local_versions is None:
262
298
  local_versions = SUPPORTED_VERSIONS
263
299
  dl.send_process_message({
264
- 'MessageName': 'Hello',
265
- 'SupportedProtocolVersions': local_versions,
300
+ "MessageName": "Hello",
301
+ "SupportedProtocolVersions": local_versions,
266
302
  })
267
303
  reply = dl.receive_message()
268
- assert reply[0] == 'DLMessageProcessMessage' and reply[1]['ErrorCode'] == 0
269
- assert reply[1]['ProtocolVersion'] in local_versions
304
+ assert reply[0] == "DLMessageProcessMessage" and reply[1]["ErrorCode"] == 0
305
+ assert reply[1]["ProtocolVersion"] in local_versions
270
306
 
271
307
  def init_mobile_backup_factory_info(self, afc: AfcService):
272
308
  with InstallationProxyService(self.lockdown) as ip, SpringBoardServicesService(self.lockdown) as sbs:
273
309
  root_node = self.lockdown.get_value()
274
- itunes_settings = self.lockdown.get_value(domain='com.apple.iTunes')
310
+ itunes_settings = self.lockdown.get_value(domain="com.apple.iTunes")
275
311
  try:
276
- min_itunes_version = self.lockdown.get_value('com.apple.mobile.iTunes', 'MinITunesVersion')
312
+ min_itunes_version = self.lockdown.get_value("com.apple.mobile.iTunes", "MinITunesVersion")
277
313
  except MissingValueError:
278
314
  # iPadOS may not contain this value. See:
279
315
  # https://github.com/doronz88/pymobiledevice3/issues/1332
280
- min_itunes_version = '10.0.1'
316
+ min_itunes_version = "10.0.1"
281
317
  app_dict = {}
282
318
  installed_apps = []
283
- apps = ip.browse(options={'ApplicationType': 'User'},
284
- attributes=['CFBundleIdentifier', 'ApplicationSINF', 'iTunesMetadata'])
319
+ apps = ip.browse(
320
+ options={"ApplicationType": "User"},
321
+ attributes=["CFBundleIdentifier", "ApplicationSINF", "iTunesMetadata"],
322
+ )
285
323
  for app in apps:
286
- bundle_id = app['CFBundleIdentifier']
324
+ bundle_id = app["CFBundleIdentifier"]
287
325
  if bundle_id:
288
326
  installed_apps.append(bundle_id)
289
- if app.get('iTunesMetadata', False) and app.get('ApplicationSINF', False):
327
+ if app.get("iTunesMetadata", False) and app.get("ApplicationSINF", False):
290
328
  app_dict[bundle_id] = {
291
- 'ApplicationSINF': app['ApplicationSINF'],
292
- 'iTunesMetadata': app['iTunesMetadata'],
293
- 'PlaceholderIcon': sbs.get_icon_pngdata(bundle_id),
329
+ "ApplicationSINF": app["ApplicationSINF"],
330
+ "iTunesMetadata": app["iTunesMetadata"],
331
+ "PlaceholderIcon": sbs.get_icon_pngdata(bundle_id),
294
332
  }
295
333
 
296
334
  files = {}
297
335
  for file in ITUNES_FILES:
298
336
  try:
299
- data_buf = afc.get_file_contents('/iTunes_Control/iTunes/' + file)
337
+ data_buf = afc.get_file_contents("/iTunes_Control/iTunes/" + file)
300
338
  except AfcFileNotFoundError:
301
339
  pass
302
340
  else:
303
341
  files[file] = data_buf
304
342
 
305
343
  ret = {
306
- 'iTunes Version': min_itunes_version if min_itunes_version else '10.0.1',
307
- 'iTunes Files': files,
308
- 'Unique Identifier': self.lockdown.udid.upper(),
309
- 'Target Type': 'Device',
310
- 'Target Identifier': root_node['UniqueDeviceID'],
311
- 'Serial Number': root_node['SerialNumber'],
312
- 'Product Version': root_node['ProductVersion'],
313
- 'Product Type': root_node['ProductType'],
314
- 'Installed Applications': installed_apps,
315
- 'GUID': uuid.uuid4().bytes,
316
- 'Display Name': root_node['DeviceName'],
317
- 'Device Name': root_node['DeviceName'],
318
- 'Build Version': root_node['BuildVersion'],
319
- 'Applications': app_dict,
344
+ "iTunes Version": min_itunes_version if min_itunes_version else "10.0.1",
345
+ "iTunes Files": files,
346
+ "Unique Identifier": self.lockdown.udid.upper(),
347
+ "Target Type": "Device",
348
+ "Target Identifier": root_node["UniqueDeviceID"],
349
+ "Serial Number": root_node["SerialNumber"],
350
+ "Product Version": root_node["ProductVersion"],
351
+ "Product Type": root_node["ProductType"],
352
+ "Installed Applications": installed_apps,
353
+ "GUID": uuid.uuid4().bytes,
354
+ "Display Name": root_node["DeviceName"],
355
+ "Device Name": root_node["DeviceName"],
356
+ "Build Version": root_node["BuildVersion"],
357
+ "Applications": app_dict,
320
358
  }
321
359
 
322
- if 'IntegratedCircuitCardIdentity' in root_node:
323
- ret['ICCID'] = root_node['IntegratedCircuitCardIdentity']
324
- if 'InternationalMobileEquipmentIdentity' in root_node:
325
- ret['IMEI'] = root_node['InternationalMobileEquipmentIdentity']
326
- if 'MobileEquipmentIdentifier' in root_node:
327
- ret['MEID'] = root_node['MobileEquipmentIdentifier']
328
- if 'PhoneNumber' in root_node:
329
- ret['Phone Number'] = root_node['PhoneNumber']
360
+ if "IntegratedCircuitCardIdentity" in root_node:
361
+ ret["ICCID"] = root_node["IntegratedCircuitCardIdentity"]
362
+ if "InternationalMobileEquipmentIdentity" in root_node:
363
+ ret["IMEI"] = root_node["InternationalMobileEquipmentIdentity"]
364
+ if "MobileEquipmentIdentifier" in root_node:
365
+ ret["MEID"] = root_node["MobileEquipmentIdentifier"]
366
+ if "PhoneNumber" in root_node:
367
+ ret["Phone Number"] = root_node["PhoneNumber"]
330
368
 
331
369
  try:
332
- data_buf = afc.get_file_contents('/Books/iBooksData2.plist')
370
+ data_buf = afc.get_file_contents("/Books/iBooksData2.plist")
333
371
  except AfcFileNotFoundError:
334
372
  pass
335
373
  else:
336
- ret['iBooks Data 2'] = data_buf
374
+ ret["iBooks Data 2"] = data_buf
337
375
  if itunes_settings:
338
- ret['iTunes Settings'] = itunes_settings
376
+ ret["iTunes Settings"] = itunes_settings
339
377
  return ret
340
378
 
341
379
  @contextmanager
342
380
  def _backup_lock(self, afc, notification_proxy):
343
381
  notification_proxy.notify_post(NP_SYNC_WILL_START)
344
- lockfile = afc.fopen('/com.apple.itunes.lock_sync', 'r+')
382
+ lockfile = afc.fopen("/com.apple.itunes.lock_sync", "r+")
345
383
  if lockfile:
346
384
  notification_proxy.notify_post(NP_SYNC_LOCK_REQUEST)
347
385
  for _ in range(50):
@@ -358,7 +396,7 @@ class Mobilebackup2Service(LockdownService):
358
396
  break
359
397
  else: # No break, lock failed.
360
398
  afc.fclose(lockfile)
361
- raise PyMobileDevice3Exception('Failed to lock itunes sync file')
399
+ raise PyMobileDevice3Exception("Failed to lock itunes sync file")
362
400
  try:
363
401
  yield
364
402
  finally:
@@ -369,9 +407,9 @@ class Mobilebackup2Service(LockdownService):
369
407
  @staticmethod
370
408
  def _assert_backup_exists(backup_directory: Path, identifier: str):
371
409
  device_directory = backup_directory / identifier
372
- assert (device_directory / 'Info.plist').exists()
373
- assert (device_directory / 'Manifest.plist').exists()
374
- assert (device_directory / 'Status.plist').exists()
410
+ assert (device_directory / "Info.plist").exists()
411
+ assert (device_directory / "Manifest.plist").exists()
412
+ assert (device_directory / "Status.plist").exists()
375
413
 
376
414
  @contextmanager
377
415
  def device_link(self, backup_directory):
@@ -1,6 +1,6 @@
1
1
  import socket
2
2
  from collections.abc import Generator
3
- from typing import Union
3
+ from typing import Optional, Union
4
4
 
5
5
  from pymobiledevice3.exceptions import NotificationTimeoutError
6
6
  from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
@@ -9,13 +9,13 @@ from pymobiledevice3.services.lockdown_service import LockdownService
9
9
 
10
10
 
11
11
  class NotificationProxyService(LockdownService):
12
- SERVICE_NAME = 'com.apple.mobile.notification_proxy'
13
- RSD_SERVICE_NAME = 'com.apple.mobile.notification_proxy.shim.remote'
12
+ SERVICE_NAME = "com.apple.mobile.notification_proxy"
13
+ RSD_SERVICE_NAME = "com.apple.mobile.notification_proxy.shim.remote"
14
14
 
15
- INSECURE_SERVICE_NAME = 'com.apple.mobile.insecure_notification_proxy'
16
- RSD_INSECURE_SERVICE_NAME = 'com.apple.mobile.insecure_notification_proxy.shim.remote'
15
+ INSECURE_SERVICE_NAME = "com.apple.mobile.insecure_notification_proxy"
16
+ RSD_INSECURE_SERVICE_NAME = "com.apple.mobile.insecure_notification_proxy.shim.remote"
17
17
 
18
- def __init__(self, lockdown: LockdownServiceProvider, insecure=False, timeout: Union[float, int] = None):
18
+ def __init__(self, lockdown: LockdownServiceProvider, insecure=False, timeout: Optional[Union[float, int]] = None):
19
19
  if isinstance(lockdown, RemoteServiceDiscoveryService):
20
20
  secure_service_name = self.RSD_SERVICE_NAME
21
21
  insecure_service_name = self.RSD_INSECURE_SERVICE_NAME
@@ -32,13 +32,13 @@ class NotificationProxyService(LockdownService):
32
32
  self.service.socket.settimeout(timeout)
33
33
 
34
34
  def notify_post(self, name: str) -> None:
35
- """ Send notification to the device's notification_proxy. """
36
- self.service.send_plist({'Command': 'PostNotification', 'Name': name})
35
+ """Send notification to the device's notification_proxy."""
36
+ self.service.send_plist({"Command": "PostNotification", "Name": name})
37
37
 
38
38
  def notify_register_dispatch(self, name: str) -> None:
39
- """ Tells the device to send a notification on the specified event. """
40
- self.logger.info(f'Observing {name}')
41
- self.service.send_plist({'Command': 'ObserveNotification', 'Name': name})
39
+ """Tells the device to send a notification on the specified event."""
40
+ self.logger.info(f"Observing {name}")
41
+ self.service.send_plist({"Command": "ObserveNotification", "Name": name})
42
42
 
43
43
  def receive_notification(self) -> Generator[dict, None, None]:
44
44
  while True: