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
@@ -15,16 +15,16 @@ from requests.structures import CaseInsensitiveDict
15
15
  from pymobiledevice3.exceptions import MobileActivationException
16
16
  from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
17
17
 
18
- ACTIVATION_USER_AGENT_IOS = 'iOS Device Activator (MobileActivation-20 built on Jan 15 2012 at 19:07:28)'
19
- ACTIVATION_DEFAULT_URL = 'https://albert.apple.com/deviceservices/deviceActivation'
20
- ACTIVATION_DRM_HANDSHAKE_DEFAULT_URL = 'https://albert.apple.com/deviceservices/drmHandshake'
18
+ ACTIVATION_USER_AGENT_IOS = "iOS Device Activator (MobileActivation-20 built on Jan 15 2012 at 19:07:28)"
19
+ ACTIVATION_DEFAULT_URL = "https://albert.apple.com/deviceservices/deviceActivation"
20
+ ACTIVATION_DRM_HANDSHAKE_DEFAULT_URL = "https://albert.apple.com/deviceservices/drmHandshake"
21
21
  DEFAULT_HEADERS = {
22
- 'Accept': 'application/xml',
23
- 'User-Agent': ACTIVATION_USER_AGENT_IOS,
24
- 'Expect': '100-continue',
22
+ "Accept": "application/xml",
23
+ "User-Agent": ACTIVATION_USER_AGENT_IOS,
24
+ "Expect": "100-continue",
25
25
  }
26
26
 
27
- ACTIVATION_REQUESTS_SUBDIR = Path('offline_requests')
27
+ ACTIVATION_REQUESTS_SUBDIR = Path("offline_requests")
28
28
  NONCE_CYCLE_INTERVAL = 60 * 5
29
29
 
30
30
 
@@ -51,7 +51,8 @@ class MobileActivationService:
51
51
  There is no point in inheriting from BaseService since we'll need a new lockdown connection
52
52
  for each request.
53
53
  """
54
- SERVICE_NAME = 'com.apple.mobileactivationd'
54
+
55
+ SERVICE_NAME = "com.apple.mobileactivationd"
55
56
 
56
57
  def __init__(self, lockdown: LockdownServiceProvider) -> None:
57
58
  self.lockdown = lockdown
@@ -60,64 +61,74 @@ class MobileActivationService:
60
61
  @property
61
62
  def state(self):
62
63
  try:
63
- return self.send_command('GetActivationStateRequest')['Value']
64
- except: # noqa
65
- return self.lockdown.get_value(key='ActivationState')
64
+ return self.send_command("GetActivationStateRequest")["Value"]
65
+ except Exception:
66
+ return self.lockdown.get_value(key="ActivationState")
66
67
 
67
68
  def wait_for_activation_session(self):
68
69
  try:
69
70
  blob = self.create_activation_session_info()
70
- except: # noqa
71
+ except Exception:
71
72
  return
72
- handshake_request_message = blob['HandshakeRequestMessage']
73
- while handshake_request_message == blob['HandshakeRequestMessage']:
73
+ handshake_request_message = blob["HandshakeRequestMessage"]
74
+ while handshake_request_message == blob["HandshakeRequestMessage"]:
74
75
  blob = self.create_activation_session_info()
75
76
 
76
77
  @staticmethod
77
78
  def _get_activation_form_from_response(content: str) -> ActivationForm:
78
79
  root = ET.fromstring(content)
79
- title = root.find('page/navigationBar').get('title')
80
- description = root.find('page/tableView/section/footer').text
80
+ title = root.find("page/navigationBar").get("title")
81
+ description = root.find("page/tableView/section/footer").text
81
82
  fields = []
82
- for editable in root.findall('page//editableTextRow'):
83
+ for editable in root.findall("page//editableTextRow"):
83
84
  fields.append(
84
- Field(id=editable.get('id'), label=editable.get('label'), placeholder=editable.get('placeholder'),
85
- secure=bool(editable.get('secure', False))))
85
+ Field(
86
+ id=editable.get("id"),
87
+ label=editable.get("label"),
88
+ placeholder=editable.get("placeholder"),
89
+ secure=bool(editable.get("secure", False)),
90
+ )
91
+ )
86
92
  server_info = {}
87
- for k, v in root.find('serverInfo').items():
93
+ for k, v in root.find("serverInfo").items():
88
94
  server_info[k] = v
89
95
  return ActivationForm(title=title, description=description, fields=fields, server_info=server_info)
90
96
 
91
97
  def activate(self, skip_apple_id_query: bool = False) -> None:
92
- if self.state != 'Unactivated':
93
- self.logger.error('Device is already activated!')
98
+ if self.state != "Unactivated":
99
+ self.logger.error("Device is already activated!")
94
100
  return
95
101
 
96
102
  try:
97
103
  blob = self.create_activation_session_info()
98
104
  session_mode = True
99
- except: # noqa
105
+ except Exception:
100
106
  session_mode = False
101
107
 
102
108
  # create drmHandshake request with blob from device
103
- headers = {'Content-Type': 'application/x-apple-plist'}
109
+ headers = {"Content-Type": "application/x-apple-plist"}
104
110
  headers.update(DEFAULT_HEADERS)
105
111
  if session_mode:
106
- content, headers = self.post(ACTIVATION_DRM_HANDSHAKE_DEFAULT_URL, data=plistlib.dumps(blob),
107
- headers=headers)
112
+ content, headers = self.post(
113
+ ACTIVATION_DRM_HANDSHAKE_DEFAULT_URL, data=plistlib.dumps(blob), headers=headers
114
+ )
108
115
 
109
116
  activation_request = {}
110
117
  if session_mode:
111
118
  activation_info = self.create_activation_info_with_session(content)
112
119
  else:
113
- activation_info = self.lockdown.get_value(key='ActivationInfo')
114
- activation_request.update(
115
- {'InStoreActivation': False, 'AppleSerialNumber': self.lockdown.get_value(key='SerialNumber')})
116
- if self.lockdown.all_values.get('TelephonyCapability'):
117
- req_pair = {'IMEI': 'InternationalMobileEquipmentIdentity',
118
- 'MEID': 'MobileEquipmentIdentifier',
119
- 'IMSI': 'InternationalMobileSubscriberIdentity',
120
- 'ICCID': 'IntegratedCircuitCardIdentity'}
120
+ activation_info = self.lockdown.get_value(key="ActivationInfo")
121
+ activation_request.update({
122
+ "InStoreActivation": False,
123
+ "AppleSerialNumber": self.lockdown.get_value(key="SerialNumber"),
124
+ })
125
+ if self.lockdown.all_values.get("TelephonyCapability"):
126
+ req_pair = {
127
+ "IMEI": "InternationalMobileEquipmentIdentity",
128
+ "MEID": "MobileEquipmentIdentifier",
129
+ "IMSI": "InternationalMobileSubscriberIdentity",
130
+ "ICCID": "IntegratedCircuitCardIdentity",
131
+ }
121
132
 
122
133
  has_meid = False
123
134
  for k, v in req_pair.items():
@@ -126,98 +137,99 @@ class MobileActivationService:
126
137
  activation_request.update({k: lv})
127
138
  continue
128
139
  else:
129
- self.logger.warn(f'Unable to get {k} from lockdownd')
130
- if k == 'MEID' and has_meid:
140
+ self.logger.warn(f"Unable to get {k} from lockdownd")
141
+ if k == "MEID" and has_meid:
131
142
  # Something is wrong if both IMEI & MEID is missing
132
- raise MobileActivationException('Unable to obtain both IMEI and MEID')
143
+ raise MobileActivationException("Unable to obtain both IMEI and MEID")
133
144
 
134
145
  # Either IMEI or MEID, or both
135
- if k == 'IMEI':
146
+ if k == "IMEI":
136
147
  has_meid = lv is None
137
- activation_request.update({'activation-info': plistlib.dumps(activation_info)})
148
+ activation_request.update({"activation-info": plistlib.dumps(activation_info)})
138
149
 
139
150
  content, headers = self.post(ACTIVATION_DEFAULT_URL, data=activation_request)
140
- content_type = headers['Content-Type']
151
+ content_type = headers["Content-Type"]
141
152
 
142
- if content_type == 'application/x-buddyml':
153
+ if content_type == "application/x-buddyml":
143
154
  if skip_apple_id_query:
144
- raise MobileActivationException('Device is iCloud locked')
155
+ raise MobileActivationException("Device is iCloud locked")
145
156
  try:
146
157
  activation_form = self._get_activation_form_from_response(content.decode())
147
- except: # noqa
148
- raise MobileActivationException('Activation server response is invalid')
158
+ except Exception as e:
159
+ raise MobileActivationException("Activation server response is invalid") from e
149
160
  else:
150
161
  click.secho(activation_form.title, bold=True)
151
162
  click.secho(activation_form.description)
152
163
  fields = []
153
164
  for field in activation_form.fields:
154
165
  if field.secure:
155
- fields.append(inquirer3.Password(name=field.id, message=f'{field.label}'))
166
+ fields.append(inquirer3.Password(name=field.id, message=f"{field.label}"))
156
167
  else:
157
- fields.append(inquirer3.Text(name=field.id, message=f'{field.label}'))
168
+ fields.append(inquirer3.Text(name=field.id, message=f"{field.label}"))
158
169
  data = inquirer3.prompt(fields)
159
170
  data.update(activation_form.server_info)
160
171
  content, headers = self.post(ACTIVATION_DEFAULT_URL, data=data)
161
- content_type = headers['Content-Type']
172
+ content_type = headers["Content-Type"]
162
173
 
163
- assert content_type == 'text/xml'
174
+ assert content_type == "text/xml"
164
175
  if session_mode:
165
176
  self.activate_with_session(content, headers)
166
177
  else:
167
178
  self.activate_with_lockdown(content)
168
179
 
169
180
  # set ActivationStateAcknowledged if we succeeded
170
- self.lockdown.set_value(True, key='ActivationStateAcknowledged')
181
+ self.lockdown.set_value(True, key="ActivationStateAcknowledged")
171
182
 
172
183
  def deactivate(self):
173
184
  try:
174
- return self.send_command('DeactivateRequest')
175
- except: # noqa
176
- return self.lockdown._request('Deactivate')
185
+ return self.send_command("DeactivateRequest")
186
+ except Exception:
187
+ return self.lockdown._request("Deactivate")
177
188
 
178
189
  def create_activation_session_info(self):
179
- response = self.send_command('CreateTunnel1SessionInfoRequest')
180
- error = response.get('Error')
190
+ response = self.send_command("CreateTunnel1SessionInfoRequest")
191
+ error = response.get("Error")
181
192
  if error is not None:
182
- raise MobileActivationException(f'Mobile activation can not be done due to: {response}')
183
- return response['Value']
193
+ raise MobileActivationException(f"Mobile activation can not be done due to: {response}")
194
+ return response["Value"]
184
195
 
185
196
  def create_activation_info_with_session(self, handshake_response):
186
- response = self.send_command('CreateTunnel1ActivationInfoRequest', handshake_response)
187
- error = response.get('Error')
197
+ response = self.send_command("CreateTunnel1ActivationInfoRequest", handshake_response)
198
+ error = response.get("Error")
188
199
  if error is not None:
189
- raise MobileActivationException(f'Mobile activation can not be done due to: {response}')
190
- return response['Value']
200
+ raise MobileActivationException(f"Mobile activation can not be done due to: {response}")
201
+ return response["Value"]
191
202
 
192
203
  def activate_with_lockdown(self, activation_record):
193
204
  record = plistlib.loads(activation_record)
194
- node = record.get('iphone-activation')
205
+ node = record.get("iphone-activation")
195
206
  if node is None:
196
- node = record.get('device-activation')
207
+ node = record.get("device-activation")
197
208
  if node is None:
198
- raise MobileActivationException('Activation record received is invalid')
209
+ raise MobileActivationException("Activation record received is invalid")
199
210
 
200
- self.lockdown._request('Activate', {'ActivationRecord': node.get('activation-record')})
211
+ self.lockdown._request("Activate", {"ActivationRecord": node.get("activation-record")})
201
212
 
202
213
  def activate_with_session(self, activation_record, headers):
203
214
  data = {
204
- 'Command': 'HandleActivationInfoWithSessionRequest',
205
- 'Value': activation_record,
215
+ "Command": "HandleActivationInfoWithSessionRequest",
216
+ "Value": activation_record,
206
217
  }
207
218
  if headers:
208
- data['ActivationResponseHeaders'] = dict(headers)
219
+ data["ActivationResponseHeaders"] = dict(headers)
209
220
  with closing(self.lockdown.start_lockdown_service(self.SERVICE_NAME)) as service:
210
221
  return service.send_recv_plist(data)
211
222
 
212
- def send_command(self, command: str, value: str = ''):
213
- data = {'Command': command}
223
+ def send_command(self, command: str, value: str = ""):
224
+ data = {"Command": command}
214
225
  if value:
215
- data['Value'] = value
226
+ data["Value"] = value
216
227
  with closing(self.lockdown.start_lockdown_service(self.SERVICE_NAME)) as service:
217
228
  return service.send_recv_plist(data)
218
229
 
219
- def post(self, url: str, data: dict, headers: Optional[CaseInsensitiveDict[str, str]] = None) \
220
- -> tuple[bytes, CaseInsensitiveDict[str]]:
230
+ def post(
231
+ self, url: str, data: dict, headers: Optional[CaseInsensitiveDict[str, str]] = None
232
+ ) -> tuple[bytes, CaseInsensitiveDict[str]]:
221
233
  if headers is None:
222
234
  headers = DEFAULT_HEADERS
223
235