pymobiledevice3 4.27.4__py3-none-any.whl → 5.1.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.
Files changed (143) hide show
  1. misc/plist_sniffer.py +15 -15
  2. misc/remotexpc_sniffer.py +29 -28
  3. pymobiledevice3/__main__.py +123 -98
  4. pymobiledevice3/_version.py +2 -2
  5. pymobiledevice3/bonjour.py +351 -117
  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 +27 -20
  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 +601 -519
  18. pymobiledevice3/cli/diagnostics.py +38 -33
  19. pymobiledevice3/cli/lockdown.py +82 -72
  20. pymobiledevice3/cli/mounter.py +84 -67
  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 +188 -111
  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 +156 -78
  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 +400 -251
  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 +64 -42
  52. pymobiledevice3/remote/tunnel_service.py +383 -297
  53. pymobiledevice3/remote/utils.py +14 -13
  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 +587 -0
  65. pymobiledevice3/restore/recovery.py +125 -135
  66. pymobiledevice3/restore/restore.py +535 -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 +137 -127
  72. pymobiledevice3/services/afc.py +352 -292
  73. pymobiledevice3/services/amfi.py +21 -18
  74. pymobiledevice3/services/companion.py +23 -19
  75. pymobiledevice3/services/crash_reports.py +61 -47
  76. pymobiledevice3/services/debugserver_applist.py +3 -3
  77. pymobiledevice3/services/device_arbitration.py +8 -8
  78. pymobiledevice3/services/device_link.py +56 -48
  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 +42 -52
  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 +331 -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 +128 -74
  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 +183 -179
  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 +3 -3
  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 +142 -116
  132. pymobiledevice3/tcp_forwarder.py +35 -22
  133. pymobiledevice3/tunneld/api.py +20 -15
  134. pymobiledevice3/tunneld/server.py +310 -193
  135. pymobiledevice3/usbmux.py +197 -148
  136. pymobiledevice3/utils.py +14 -11
  137. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/METADATA +1 -2
  138. pymobiledevice3-5.1.2.dist-info/RECORD +173 -0
  139. pymobiledevice3-4.27.4.dist-info/RECORD +0 -172
  140. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/WHEEL +0 -0
  141. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/entry_points.txt +0 -0
  142. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/licenses/LICENSE +0 -0
  143. {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/top_level.txt +0 -0
@@ -9,8 +9,6 @@ from enum import IntEnum
9
9
  from pathlib import Path
10
10
  from tarfile import TarFile
11
11
 
12
- from construct import Adapter, Byte, Bytes, Computed, Enum, Int16ul, Int32ul, Optional, RepeatUntil, Struct, this
13
-
14
12
  from pymobiledevice3.exceptions import PyMobileDevice3Exception
15
13
  from pymobiledevice3.lockdown import LockdownClient
16
14
  from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
@@ -18,8 +16,8 @@ from pymobiledevice3.services.lockdown_service import LockdownService
18
16
  from pymobiledevice3.utils import try_decode
19
17
 
20
18
  CHUNK_SIZE = 4096
21
- TIME_FORMAT = '%H:%M:%S'
22
- SYSLOG_LINE_SPLITTER = '\n\x00'
19
+ TIME_FORMAT = "%H:%M:%S"
20
+ SYSLOG_LINE_SPLITTER = "\n\x00"
23
21
 
24
22
 
25
23
  class SyslogLogLevel(IntEnum):
@@ -50,47 +48,96 @@ class SyslogEntry:
50
48
  label: typing.Optional[SyslogLabel] = None
51
49
 
52
50
 
53
- class TimestampAdapter(Adapter):
54
- def _decode(self, obj, context, path):
55
- return datetime.fromtimestamp(obj.seconds + (obj.microseconds / 1000000))
56
-
57
- def _encode(self, obj, context, path):
58
- return list(map(int, obj.split(".")))
59
-
60
-
61
- timestamp_t = Struct(
62
- 'seconds' / Int32ul,
63
- Bytes(4),
64
- 'microseconds' / Int32ul
65
- )
66
-
67
- syslog_t = Struct(
68
- Bytes(9),
69
- 'pid' / Int32ul,
70
- Bytes(42),
71
- 'timestamp' / TimestampAdapter(timestamp_t),
72
- Bytes(1),
73
- 'level' / Enum(Byte, Notice=0, Info=0x01, Debug=0x02, Error=0x10, Fault=0x11),
74
- Bytes(38),
75
- 'image_name_size' / Int16ul,
76
- 'message_size' / Int16ul,
77
- Bytes(6),
78
- '_subsystem_size' / Int32ul,
79
- '_category_size' / Int32ul,
80
- Bytes(4),
81
- '_filename' / RepeatUntil(lambda x, lst, ctx: lst[-1] == 0, Byte),
82
- 'filename' / Computed(lambda ctx: try_decode(bytearray(ctx._filename[:-1]))),
83
- '_image_name' / Bytes(this.image_name_size),
84
- 'image_name' / Computed(lambda ctx: try_decode(ctx._image_name[:-1])),
85
- '_message' / Bytes(this.message_size),
86
- 'message' / Computed(lambda ctx: try_decode(ctx._message[:-1])),
87
- 'label' / Optional(Struct(
88
- '_subsystem' / Bytes(this._._subsystem_size),
89
- 'subsystem' / Computed(lambda ctx: try_decode(ctx._subsystem[:-1])),
90
- '_category' / Bytes(this._._category_size),
91
- 'category' / Computed(lambda ctx: try_decode(ctx._category[:-1])),
92
- )),
93
- )
51
+ def parse_syslog_entry(data: bytes) -> SyslogEntry:
52
+ """
53
+ Parse a syslog entry from binary data.
54
+
55
+ :param data: Raw binary data
56
+ :return: SyslogEntry
57
+ """
58
+ offset = 0
59
+
60
+ # Skip first 9 bytes
61
+ offset += 9
62
+
63
+ # Parse pid (4 bytes, little-endian unsigned int)
64
+ pid = struct.unpack("<I", data[offset : offset + 4])[0]
65
+ offset += 4
66
+
67
+ # Skip 42 bytes
68
+ offset += 42
69
+
70
+ # Parse timestamp
71
+ seconds = struct.unpack("<I", data[offset : offset + 4])[0]
72
+ offset += 4
73
+ offset += 4 # Skip 4 bytes
74
+ microseconds = struct.unpack("<I", data[offset : offset + 4])[0]
75
+ offset += 4
76
+ timestamp = datetime.fromtimestamp(seconds + (microseconds / 1000000))
77
+
78
+ # Skip 1 byte
79
+ offset += 1
80
+
81
+ # Parse level (1 byte)
82
+ level = data[offset]
83
+ offset += 1
84
+
85
+ # Skip 38 bytes
86
+ offset += 38
87
+
88
+ # Parse image_name_size (2 bytes, little-endian unsigned short)
89
+ image_name_size = struct.unpack("<H", data[offset : offset + 2])[0]
90
+ offset += 2
91
+
92
+ # Parse message_size (2 bytes, little-endian unsigned short)
93
+ message_size = struct.unpack("<H", data[offset : offset + 2])[0]
94
+ offset += 2
95
+
96
+ # Skip 6 bytes
97
+ offset += 6
98
+
99
+ # Parse subsystem_size (4 bytes, little-endian unsigned int)
100
+ subsystem_size = struct.unpack("<I", data[offset : offset + 4])[0]
101
+ offset += 4
102
+
103
+ # Parse category_size (4 bytes, little-endian unsigned int)
104
+ category_size = struct.unpack("<I", data[offset : offset + 4])[0]
105
+ offset += 4
106
+
107
+ # Skip 4 bytes
108
+ offset += 4
109
+
110
+ # Parse filename (null-terminated)
111
+ filename_end = data.find(b"\x00", offset)
112
+ filename = try_decode(data[offset:filename_end])
113
+ offset = filename_end + 1
114
+
115
+ # Parse image_name
116
+ image_name = try_decode(data[offset : offset + image_name_size - 1])
117
+ offset += image_name_size
118
+
119
+ # Parse message
120
+ message = try_decode(data[offset : offset + message_size - 1])
121
+ offset += message_size
122
+
123
+ # Parse label (optional)
124
+ label = None
125
+ if subsystem_size > 0 and category_size > 0:
126
+ subsystem = try_decode(data[offset : offset + subsystem_size - 1])
127
+ offset += subsystem_size
128
+ category = try_decode(data[offset : offset + category_size - 1])
129
+ offset += category_size
130
+ label = SyslogLabel(subsystem=subsystem, category=category)
131
+
132
+ return SyslogEntry(
133
+ pid=pid,
134
+ timestamp=timestamp,
135
+ level=SyslogLogLevel(level),
136
+ image_name=image_name,
137
+ filename=filename,
138
+ message=message,
139
+ label=label,
140
+ )
94
141
 
95
142
 
96
143
  class OsTraceService(LockdownService):
@@ -101,8 +148,9 @@ class OsTraceService(LockdownService):
101
148
  * Get old stored syslog archive in PAX format (can be extracted using `pax -r < filename`).
102
149
  * Archive contain the contents are the `/var/db/diagnostics` directory
103
150
  """
104
- SERVICE_NAME = 'com.apple.os_trace_relay'
105
- RSD_SERVICE_NAME = 'com.apple.os_trace_relay.shim.remote'
151
+
152
+ SERVICE_NAME = "com.apple.os_trace_relay"
153
+ RSD_SERVICE_NAME = "com.apple.os_trace_relay.shim.remote"
106
154
 
107
155
  def __init__(self, lockdown: LockdownServiceProvider):
108
156
  if isinstance(lockdown, LockdownClient):
@@ -111,7 +159,7 @@ class OsTraceService(LockdownService):
111
159
  super().__init__(lockdown, self.RSD_SERVICE_NAME)
112
160
 
113
161
  def get_pid_list(self):
114
- self.service.send_plist({'Request': 'PidList'})
162
+ self.service.send_plist({"Request": "PidList"})
115
163
 
116
164
  # ignore first received unknown byte
117
165
  self.service.recvall(1)
@@ -119,33 +167,44 @@ class OsTraceService(LockdownService):
119
167
  response = self.service.recv_prefixed()
120
168
  return plistlib.loads(response)
121
169
 
122
- def create_archive(self, out: typing.IO, size_limit: int = None, age_limit: int = None, start_time: int = None):
123
- request = {'Request': 'CreateArchive'}
170
+ def create_archive(
171
+ self,
172
+ out: typing.IO,
173
+ size_limit: typing.Optional[int] = None,
174
+ age_limit: typing.Optional[int] = None,
175
+ start_time: typing.Optional[int] = None,
176
+ ):
177
+ request = {"Request": "CreateArchive"}
124
178
 
125
179
  if size_limit is not None:
126
- request.update({'SizeLimit': size_limit})
180
+ request.update({"SizeLimit": size_limit})
127
181
 
128
182
  if age_limit is not None:
129
- request.update({'AgeLimit': age_limit})
183
+ request.update({"AgeLimit": age_limit})
130
184
 
131
185
  if start_time is not None:
132
- request.update({'StartTime': start_time})
186
+ request.update({"StartTime": start_time})
133
187
 
134
188
  self.service.send_plist(request)
135
189
 
136
- assert 1 == self.service.recvall(1)[0]
190
+ assert self.service.recvall(1)[0] == 1
137
191
 
138
- assert plistlib.loads(self.service.recv_prefixed()).get('Status') == 'RequestSuccessful', 'Invalid status'
192
+ assert plistlib.loads(self.service.recv_prefixed()).get("Status") == "RequestSuccessful", "Invalid status"
139
193
 
140
194
  while True:
141
195
  try:
142
- assert 3 == self.service.recvall(1)[0], 'invalid magic'
196
+ assert self.service.recvall(1)[0] == 3, "invalid magic"
143
197
  except ConnectionAbortedError:
144
198
  break
145
- out.write(self.service.recv_prefixed(endianity='<'))
146
-
147
- def collect(self, out: str, size_limit: typing.Optional[int] = None, age_limit: typing.Optional[int] = None,
148
- start_time: typing.Optional[int] = None) -> None:
199
+ out.write(self.service.recv_prefixed(endianity="<"))
200
+
201
+ def collect(
202
+ self,
203
+ out: str,
204
+ size_limit: typing.Optional[int] = None,
205
+ age_limit: typing.Optional[int] = None,
206
+ start_time: typing.Optional[int] = None,
207
+ ) -> None:
149
208
  """
150
209
  Collect the system logs into a .logarchive that can be viewed later with tools such as log or Console.
151
210
 
@@ -155,28 +214,23 @@ class OsTraceService(LockdownService):
155
214
  :param start_time: start time of logarchive in unix timestamp
156
215
  """
157
216
  with tempfile.TemporaryDirectory() as temp_dir:
158
- file = Path(temp_dir) / 'foo.tar'
159
- with open(file, 'wb') as f:
217
+ file = Path(temp_dir) / "foo.tar"
218
+ with open(file, "wb") as f:
160
219
  self.create_archive(f, size_limit=size_limit, age_limit=age_limit, start_time=start_time)
161
220
  TarFile(file).extractall(out)
162
221
 
163
222
  def syslog(self, pid=-1) -> typing.Generator[SyslogEntry, None, None]:
164
- self.service.send_plist({'Request': 'StartActivity', 'MessageFilter': 65535, 'Pid': pid, 'StreamFlags': 60})
223
+ self.service.send_plist({"Request": "StartActivity", "MessageFilter": 65535, "Pid": pid, "StreamFlags": 60})
165
224
 
166
- length_length, = struct.unpack('<I', self.service.recvall(4))
225
+ (length_length,) = struct.unpack("<I", self.service.recvall(4))
167
226
  length = int(self.service.recvall(length_length)[::-1].hex(), 16)
168
227
  response = plistlib.loads(self.service.recvall(length))
169
228
 
170
- if response.get('Status') != 'RequestSuccessful':
171
- raise PyMobileDevice3Exception(f'got invalid response: {response}')
229
+ if response.get("Status") != "RequestSuccessful":
230
+ raise PyMobileDevice3Exception(f"got invalid response: {response}")
172
231
 
173
232
  while True:
174
- assert b'\x02' == self.service.recvall(1)
175
- length, = struct.unpack('<I', self.service.recvall(4))
233
+ assert self.service.recvall(1) == b"\x02"
234
+ (length,) = struct.unpack("<I", self.service.recvall(4))
176
235
  line = self.service.recvall(length)
177
- entry = syslog_t.parse(line)
178
- label = None
179
- if entry.label is not None:
180
- label = SyslogLabel(subsystem=entry.label.subsystem, category=entry.label.category)
181
- yield SyslogEntry(pid=entry.pid, timestamp=entry.timestamp, level=SyslogLogLevel(int(entry.level)),
182
- image_name=entry.image_name, filename=entry.filename, message=entry.message, label=label)
236
+ yield parse_syslog_entry(line)