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,20 +1,34 @@
1
1
  import asyncio
2
+ import contextlib
2
3
  import sys
3
4
  from asyncio import IncompleteReadError
4
- from collections.abc import Generator
5
+ from collections.abc import AsyncIterable
5
6
  from typing import Optional
6
7
 
7
8
  import IPython
8
9
  import nest_asyncio
9
10
  from construct import StreamError
10
- from hyperframe.frame import DataFrame, Frame, GoAwayFrame, HeadersFrame, RstStreamFrame, SettingsFrame, \
11
- WindowUpdateFrame
11
+ from hyperframe.frame import (
12
+ DataFrame,
13
+ Frame,
14
+ GoAwayFrame,
15
+ HeadersFrame,
16
+ RstStreamFrame,
17
+ SettingsFrame,
18
+ WindowUpdateFrame,
19
+ )
12
20
  from pygments import formatters, highlight, lexers
13
21
  from traitlets.config import Config
14
22
 
15
- from pymobiledevice3.exceptions import StreamClosedError
16
- from pymobiledevice3.remote.xpc_message import XpcFlags, XpcInt64Type, XpcUInt64Type, XpcWrapper, create_xpc_wrapper, \
17
- decode_xpc_object
23
+ from pymobiledevice3.exceptions import ProtocolError, StreamClosedError
24
+ from pymobiledevice3.remote.xpc_message import (
25
+ XpcFlags,
26
+ XpcInt64Type,
27
+ XpcUInt64Type,
28
+ XpcWrapper,
29
+ create_xpc_wrapper,
30
+ decode_xpc_object,
31
+ )
18
32
 
19
33
  # Extracted by sniffing `remoted` traffic via Wireshark
20
34
  DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS = 100
@@ -22,11 +36,13 @@ DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE = 1048576
22
36
  DEFAULT_WIN_SIZE_INCR = 983041
23
37
 
24
38
  FRAME_HEADER_SIZE = 9
25
- HTTP2_MAGIC = b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'
39
+ HTTP2_MAGIC = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
26
40
 
27
41
  ROOT_CHANNEL = 1
28
42
  REPLY_CHANNEL = 3
29
43
 
44
+ FIRST_REPLY_TIMEOUT = 3
45
+
30
46
  SHELL_USAGE = """
31
47
  # This shell allows you to communicate directly with every RemoteXPC service.
32
48
 
@@ -37,14 +53,14 @@ resp = await client.send_receive_request({"Command": "DoSomething"})
37
53
 
38
54
  class RemoteXPCConnection:
39
55
  def __init__(self, address: tuple[str, int]):
40
- self._previous_frame_data = b''
56
+ self._previous_frame_data = b""
41
57
  self.address = address
42
58
  self.next_message_id: dict[int, int] = {ROOT_CHANNEL: 0, REPLY_CHANNEL: 0}
43
59
  self.peer_info = None
44
60
  self._reader: Optional[asyncio.StreamReader] = None
45
61
  self._writer: Optional[asyncio.StreamWriter] = None
46
62
 
47
- async def __aenter__(self) -> 'RemoteXPCConnection':
63
+ async def __aenter__(self) -> "RemoteXPCConnection":
48
64
  await self.connect()
49
65
  return self
50
66
 
@@ -53,33 +69,36 @@ class RemoteXPCConnection:
53
69
 
54
70
  async def connect(self) -> None:
55
71
  self._reader, self._writer = await asyncio.open_connection(self.address[0], self.address[1])
56
- await self._do_handshake()
72
+ try:
73
+ await self._do_handshake()
74
+ except Exception:
75
+ await self.close()
76
+ raise
57
77
 
58
78
  async def close(self) -> None:
59
79
  if self._writer is None:
60
80
  return
61
81
  self._writer.close()
62
- try:
82
+ with contextlib.suppress(ConnectionResetError):
63
83
  await self._writer.wait_closed()
64
- except ConnectionResetError:
65
- pass
66
84
  self._writer = None
67
85
  self._reader = None
68
86
 
69
87
  async def send_request(self, data: dict, wanting_reply: bool = False) -> None:
70
88
  xpc_wrapper = create_xpc_wrapper(
71
- data, message_id=self.next_message_id[ROOT_CHANNEL], wanting_reply=wanting_reply)
89
+ data, message_id=self.next_message_id[ROOT_CHANNEL], wanting_reply=wanting_reply
90
+ )
72
91
  self._writer.write(DataFrame(stream_id=ROOT_CHANNEL, data=xpc_wrapper).serialize())
73
92
  await self._writer.drain()
74
93
 
75
- async def iter_file_chunks(self, total_size: int, file_idx: int = 0) -> Generator[bytes, None, None]:
94
+ async def iter_file_chunks(self, total_size: int, file_idx: int = 0) -> AsyncIterable[bytes]:
76
95
  stream_id = (file_idx + 1) * 2
77
96
  await self._open_channel(stream_id, XpcFlags.FILE_TX_STREAM_RESPONSE)
78
97
  size = 0
79
98
  while size < total_size:
80
99
  frame = await self._receive_next_data_frame()
81
100
 
82
- if 'END_STREAM' in frame.flags:
101
+ if "END_STREAM" in frame.flags:
83
102
  continue
84
103
 
85
104
  if frame.stream_id != stream_id:
@@ -87,12 +106,12 @@ class RemoteXPCConnection:
87
106
  if xpc_wrapper.flags.FILE_TX_STREAM_REQUEST:
88
107
  continue
89
108
 
90
- assert frame.stream_id == stream_id, f'got {frame.stream_id} instead of {stream_id}'
109
+ assert frame.stream_id == stream_id, f"got {frame.stream_id} instead of {stream_id}"
91
110
  size += len(frame.data)
92
111
  yield frame.data
93
112
 
94
113
  async def receive_file(self, total_size: int) -> bytes:
95
- buf = b''
114
+ buf = b""
96
115
  async for chunk in self.iter_file_chunks(total_size):
97
116
  buf += chunk
98
117
  return buf
@@ -102,7 +121,7 @@ class RemoteXPCConnection:
102
121
  frame = await self._receive_next_data_frame()
103
122
  try:
104
123
  xpc_message = XpcWrapper.parse(self._previous_frame_data + frame.data).message
105
- self._previous_frame_data = b''
124
+ self._previous_frame_data = b""
106
125
  except StreamError:
107
126
  self._previous_frame_data += frame.data
108
127
  continue
@@ -119,46 +138,56 @@ class RemoteXPCConnection:
119
138
 
120
139
  def shell(self) -> None:
121
140
  nest_asyncio.apply(asyncio.get_running_loop())
122
- sys.argv = ['a']
141
+ sys.argv = ["a"]
123
142
  config = Config()
124
- config.InteractiveShellApp.exec_lines = ['%autoawait asyncio']
125
- print(highlight(SHELL_USAGE, lexers.PythonLexer(),
126
- formatters.Terminal256Formatter(style='native')))
127
- IPython.start_ipython(config=config, user_ns={
128
- 'client': self,
129
- 'XpcInt64Type': XpcInt64Type,
130
- 'XpcUInt64Type': XpcUInt64Type,
131
- })
143
+ config.InteractiveShellApp.exec_lines = ["%autoawait asyncio"]
144
+ print(highlight(SHELL_USAGE, lexers.PythonLexer(), formatters.Terminal256Formatter(style="native")))
145
+ IPython.start_ipython(
146
+ config=config,
147
+ user_ns={
148
+ "client": self,
149
+ "XpcInt64Type": XpcInt64Type,
150
+ "XpcUInt64Type": XpcUInt64Type,
151
+ },
152
+ )
132
153
 
133
154
  async def _do_handshake(self) -> None:
134
155
  self._writer.write(HTTP2_MAGIC)
135
156
  await self._writer.drain()
136
157
 
137
158
  # send h2 headers
138
- await self._send_frame(SettingsFrame(settings={
139
- SettingsFrame.MAX_CONCURRENT_STREAMS: DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS,
140
- SettingsFrame.INITIAL_WINDOW_SIZE: DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE,
141
- }))
159
+ await self._send_frame(
160
+ SettingsFrame(
161
+ settings={
162
+ SettingsFrame.MAX_CONCURRENT_STREAMS: DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS,
163
+ SettingsFrame.INITIAL_WINDOW_SIZE: DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE,
164
+ }
165
+ )
166
+ )
142
167
  await self._send_frame(WindowUpdateFrame(stream_id=0, window_increment=DEFAULT_WIN_SIZE_INCR))
143
- await self._send_frame(HeadersFrame(stream_id=ROOT_CHANNEL, flags=['END_HEADERS']))
168
+ await self._send_frame(HeadersFrame(stream_id=ROOT_CHANNEL, flags=["END_HEADERS"]))
144
169
 
145
170
  # send first actual requests
146
171
  await self.send_request({})
147
- await self._send_frame(DataFrame(stream_id=ROOT_CHANNEL,
148
- data=XpcWrapper.build({'size': 0, 'flags': 0x0201, 'payload': None})))
172
+ await self._send_frame(
173
+ DataFrame(stream_id=ROOT_CHANNEL, data=XpcWrapper.build({"size": 0, "flags": 0x0201, "payload": None}))
174
+ )
149
175
  self.next_message_id[ROOT_CHANNEL] += 1
150
176
  await self._open_channel(REPLY_CHANNEL, XpcFlags.INIT_HANDSHAKE)
151
177
  self.next_message_id[REPLY_CHANNEL] += 1
152
178
 
153
- assert isinstance(await self._receive_frame(), SettingsFrame)
179
+ settings_frame = await asyncio.wait_for(self._receive_frame(), FIRST_REPLY_TIMEOUT)
180
+ if not isinstance(settings_frame, SettingsFrame):
181
+ raise ProtocolError(f"Got unexpected frame: {settings_frame} instead of a SettingsFrame")
154
182
 
155
- await self._send_frame(SettingsFrame(flags=['ACK']))
183
+ await self._send_frame(SettingsFrame(flags=["ACK"]))
156
184
 
157
185
  async def _open_channel(self, stream_id: int, flags: int) -> None:
158
186
  flags |= XpcFlags.ALWAYS_SET
159
- await self._send_frame(HeadersFrame(stream_id=stream_id, flags=['END_HEADERS']))
187
+ await self._send_frame(HeadersFrame(stream_id=stream_id, flags=["END_HEADERS"]))
160
188
  await self._send_frame(
161
- DataFrame(stream_id=stream_id, data=XpcWrapper.build({'size': 0, 'flags': flags, 'payload': None})))
189
+ DataFrame(stream_id=stream_id, data=XpcWrapper.build({"size": 0, "flags": flags, "payload": None}))
190
+ )
162
191
 
163
192
  async def _send_frame(self, frame: Frame) -> None:
164
193
  self._writer.write(frame.serialize())
@@ -169,9 +198,9 @@ class RemoteXPCConnection:
169
198
  frame = await self._receive_frame()
170
199
 
171
200
  if isinstance(frame, GoAwayFrame):
172
- raise StreamClosedError(f'Got {frame}')
201
+ raise StreamClosedError(f"Got {frame}")
173
202
  if isinstance(frame, RstStreamFrame):
174
- raise StreamClosedError(f'Got {frame}')
203
+ raise StreamClosedError(f"Got {frame}")
175
204
  if not isinstance(frame, DataFrame):
176
205
  continue
177
206
 
@@ -188,11 +217,11 @@ class RemoteXPCConnection:
188
217
  return frame
189
218
 
190
219
  async def _recvall(self, size: int) -> bytes:
191
- data = b''
220
+ data = b""
192
221
  while len(data) < size:
193
222
  try:
194
223
  chunk = await self._reader.readexactly(size - len(data))
195
- except IncompleteReadError:
196
- raise ConnectionAbortedError()
224
+ except IncompleteReadError as e:
225
+ raise ConnectionAbortedError() from e
197
226
  data += chunk
198
227
  return data