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
@@ -3,6 +3,7 @@
3
3
  # - Uses ifaddr (optional) to map IPs -> local interfaces; otherwise iface will be None.
4
4
 
5
5
  import asyncio
6
+ import contextlib
6
7
  import ipaddress
7
8
  import socket
8
9
  import struct
@@ -15,10 +16,10 @@ import ifaddr # pip install ifaddr
15
16
 
16
17
  from pymobiledevice3.osu.os_utils import get_os_utils
17
18
 
18
- REMOTEPAIRING_SERVICE_NAME = '_remotepairing._tcp.local.'
19
- REMOTEPAIRING_MANUAL_PAIRING_SERVICE_NAME = '_remotepairing-manual-pairing._tcp.local.'
20
- MOBDEV2_SERVICE_NAME = '_apple-mobdev2._tcp.local.'
21
- REMOTED_SERVICE_NAME = '_remoted._tcp.local.'
19
+ REMOTEPAIRING_SERVICE_NAME = "_remotepairing._tcp.local."
20
+ REMOTEPAIRING_MANUAL_PAIRING_SERVICE_NAME = "_remotepairing-manual-pairing._tcp.local."
21
+ MOBDEV2_SERVICE_NAME = "_apple-mobdev2._tcp.local."
22
+ REMOTED_SERVICE_NAME = "_remoted._tcp.local."
22
23
  OSUTILS = get_os_utils()
23
24
  DEFAULT_BONJOUR_TIMEOUT = OSUTILS.bonjour_timeout
24
25
 
@@ -38,6 +39,7 @@ CLASS_QU = 0x8000 # unicast-response bit (we use multicast queries)
38
39
 
39
40
  # ---------------- Dataclasses ----------------
40
41
 
42
+
41
43
  # --- Dataclass decorator shim (adds slots only on 3.10+)
42
44
  def dataclass_compat(*d_args, **d_kwargs):
43
45
  if sys.version_info < (3, 10):
@@ -123,9 +125,9 @@ def parse_rr(data: bytes, off: int):
123
125
  name, off = decode_name(data, off)
124
126
  if off + 10 > len(data):
125
127
  raise ValueError("truncated RR header")
126
- rtype, rclass, ttl, rdlen = struct.unpack("!HHIH", data[off: off + 10])
128
+ rtype, rclass, ttl, rdlen = struct.unpack("!HHIH", data[off : off + 10])
127
129
  off += 10
128
- rdata = data[off: off + rdlen]
130
+ rdata = data[off : off + rdlen]
129
131
  off += rdlen
130
132
 
131
133
  rr = {"name": name, "type": rtype, "class": rclass & 0x7FFF, "ttl": ttl}
@@ -135,16 +137,14 @@ def parse_rr(data: bytes, off: int):
135
137
  elif rtype == QTYPE_SRV and rdlen >= 6:
136
138
  priority, weight, port = struct.unpack("!HHH", rdata[:6])
137
139
  target, _ = decode_name(data, off - rdlen + 6)
138
- rr.update(
139
- {"priority": priority, "weight": weight, "port": port, "target": target}
140
- )
140
+ rr.update({"priority": priority, "weight": weight, "port": port, "target": target})
141
141
  elif rtype == QTYPE_TXT:
142
142
  kv = {}
143
143
  i = 0
144
144
  while i < rdlen:
145
145
  b = rdata[i]
146
146
  i += 1
147
- seg = rdata[i: i + b]
147
+ seg = rdata[i : i + b]
148
148
  i += b
149
149
  if not seg:
150
150
  continue
@@ -185,16 +185,13 @@ class _Adapters:
185
185
  def __init__(self):
186
186
  self.adapters = ifaddr.get_adapters() if ifaddr is not None else []
187
187
 
188
- def pick_iface_for_ip(
189
- self, ip_str: str, family: int, v6_scopeid: Optional[int]
190
- ) -> Optional[str]:
188
+ def pick_iface_for_ip(self, ip_str: str, family: int, v6_scopeid: Optional[int]) -> Optional[str]:
191
189
  # Prefer scope id for IPv6 link-local
192
- if family == socket.AF_INET6 and ip_str.lower().startswith("fe80:"):
193
- if v6_scopeid:
194
- try:
195
- return socket.if_indextoname(v6_scopeid)
196
- except OSError:
197
- pass
190
+ if family == socket.AF_INET6 and ip_str.lower().startswith("fe80:") and v6_scopeid:
191
+ try:
192
+ return socket.if_indextoname(v6_scopeid)
193
+ except OSError:
194
+ pass
198
195
 
199
196
  # Otherwise, try to match destination ip to local subnet via ifaddr
200
197
  if not self.adapters:
@@ -213,9 +210,7 @@ class _Adapters:
213
210
  ipn_ip = ipn.ip[0]
214
211
  if fam != family:
215
212
  continue
216
- net = ipaddress.ip_network(
217
- f"{ipn_ip}/{ipn.network_prefix}", strict=False
218
- )
213
+ net = ipaddress.ip_network(f"{ipn_ip}/{ipn.network_prefix}", strict=False)
219
214
  if ip in net and ipn.network_prefix > best[1]:
220
215
  best = (ad.nice_name or ad.name, ipn.network_prefix)
221
216
  return best[0]
@@ -237,21 +232,15 @@ async def _bind_ipv4(queue: asyncio.Queue):
237
232
  s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
238
233
  s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
239
234
  if hasattr(socket, "SO_REUSEPORT"):
240
- try:
235
+ with contextlib.suppress(OSError):
241
236
  s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
242
- except OSError:
243
- pass
244
237
  s.bind(("0.0.0.0", MDNS_PORT))
245
238
  try:
246
- mreq = struct.pack(
247
- "=4s4s", socket.inet_aton(MDNS_MCAST_V4), socket.inet_aton("0.0.0.0")
248
- )
239
+ mreq = struct.pack("=4s4s", socket.inet_aton(MDNS_MCAST_V4), socket.inet_aton("0.0.0.0"))
249
240
  s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
250
241
  except OSError:
251
242
  pass
252
- transport, _ = await asyncio.get_running_loop().create_datagram_endpoint(
253
- lambda: _DatagramProtocol(queue), sock=s
254
- )
243
+ transport, _ = await asyncio.get_running_loop().create_datagram_endpoint(lambda: _DatagramProtocol(queue), sock=s)
255
244
  return transport, s
256
245
 
257
246
 
@@ -259,10 +248,8 @@ async def _bind_ipv6_all_ifaces(queue: asyncio.Queue):
259
248
  s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
260
249
  s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
261
250
  if hasattr(socket, "SO_REUSEPORT"):
262
- try:
251
+ with contextlib.suppress(OSError):
263
252
  s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
264
- except OSError:
265
- pass
266
253
  s.bind(("::", MDNS_PORT))
267
254
  grp = socket.inet_pton(socket.AF_INET6, MDNS_MCAST_V6)
268
255
  for ifindex, _ in socket.if_nameindex():
@@ -271,9 +258,7 @@ async def _bind_ipv6_all_ifaces(queue: asyncio.Queue):
271
258
  s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq6)
272
259
  except OSError:
273
260
  continue
274
- transport, _ = await asyncio.get_running_loop().create_datagram_endpoint(
275
- lambda: _DatagramProtocol(queue), sock=s
276
- )
261
+ transport, _ = await asyncio.get_running_loop().create_datagram_endpoint(lambda: _DatagramProtocol(queue), sock=s)
277
262
  return transport, s
278
263
 
279
264
 
@@ -302,9 +287,7 @@ async def _send_query_all(transports, pkt: bytes):
302
287
  # ---------------- Public API ----------------
303
288
 
304
289
 
305
- async def browse_service(
306
- service_type: str, timeout: float = 4.0
307
- ) -> List[ServiceInstance]:
290
+ async def browse_service(service_type: str, timeout: float = 4.0) -> List[ServiceInstance]:
308
291
  """
309
292
  Discover a DNS-SD/mDNS service type (e.g. "_remoted._tcp.local.") on the local network.
310
293
 
@@ -335,16 +318,12 @@ async def browse_service(
335
318
  existing.append(Address(ip=ip_str, iface=iface))
336
319
 
337
320
  try:
338
- await _send_query_all(
339
- transports, build_query(service_type, QTYPE_PTR, unicast=False)
340
- )
321
+ await _send_query_all(transports, build_query(service_type, QTYPE_PTR, unicast=False))
341
322
  loop = asyncio.get_running_loop()
342
323
  end = loop.time() + timeout
343
324
  while loop.time() < end:
344
325
  try:
345
- data, pkt_addr = await asyncio.wait_for(
346
- queue.get(), timeout=end - loop.time()
347
- )
326
+ data, pkt_addr = await asyncio.wait_for(queue.get(), timeout=end - loop.time())
348
327
  except asyncio.TimeoutError:
349
328
  break
350
329
  for rr in parse_mdns_message(data):
@@ -358,9 +337,7 @@ async def browse_service(
358
337
  }
359
338
  elif t == QTYPE_TXT:
360
339
  txt_map[rr["name"]] = rr.get("txt", {})
361
- elif t == QTYPE_A and rr.get("address"):
362
- _record_addr(rr["name"], rr["address"], pkt_addr)
363
- elif t == QTYPE_AAAA and rr.get("address"):
340
+ elif (t == QTYPE_A and rr.get("address")) or (t == QTYPE_AAAA and rr.get("address")):
364
341
  _record_addr(rr["name"], rr["address"], pkt_addr)
365
342
  finally:
366
343
  for transport, _ in transports:
pymobiledevice3/ca.py CHANGED
@@ -23,10 +23,7 @@ def select_hash_algorithm(device_version: Union[tuple[int, int, int], str, None]
23
23
  """
24
24
  if device_version is None:
25
25
  return hashes.SHA256()
26
- if isinstance(device_version, str):
27
- parts = tuple(int(x) for x in device_version.split("."))
28
- else:
29
- parts = device_version
26
+ parts = tuple(int(x) for x in device_version.split(".")) if isinstance(device_version, str) else device_version
30
27
  return hashes.SHA1() if parts < (4, 0, 0) else hashes.SHA256()
31
28
 
32
29
 
@@ -65,6 +62,7 @@ def serialize_private_key_pkcs8_pem(key: RSAPrivateKey) -> bytes:
65
62
  # Certificate builders (empty DN, v3, KU)
66
63
  # =======================================
67
64
 
65
+
68
66
  def build_root_certificate(root_key: RSAPrivateKey, alg: hashes.HashAlgorithm) -> Certificate:
69
67
  """
70
68
  Build a self-signed root (CA) certificate:
@@ -93,10 +91,10 @@ def build_root_certificate(root_key: RSAPrivateKey, alg: hashes.HashAlgorithm) -
93
91
 
94
92
 
95
93
  def build_host_certificate(
96
- host_key: RSAPrivateKey,
97
- root_cert: Certificate,
98
- root_key: RSAPrivateKey,
99
- alg: hashes.HashAlgorithm,
94
+ host_key: RSAPrivateKey,
95
+ root_cert: Certificate,
96
+ root_key: RSAPrivateKey,
97
+ alg: hashes.HashAlgorithm,
100
98
  ) -> Certificate:
101
99
  """
102
100
  Build the host (leaf) certificate signed by the root:
@@ -127,9 +125,13 @@ def build_host_certificate(
127
125
  x509.KeyUsage(
128
126
  digital_signature=True,
129
127
  key_encipherment=True,
130
- key_cert_sign=False, crl_sign=False,
131
- content_commitment=False, data_encipherment=False,
132
- key_agreement=False, encipher_only=False, decipher_only=False,
128
+ key_cert_sign=False,
129
+ crl_sign=False,
130
+ content_commitment=False,
131
+ data_encipherment=False,
132
+ key_agreement=False,
133
+ encipher_only=False,
134
+ decipher_only=False,
133
135
  ),
134
136
  critical=True,
135
137
  )
@@ -138,10 +140,10 @@ def build_host_certificate(
138
140
 
139
141
 
140
142
  def build_device_certificate(
141
- device_public_key: RSAPublicKey,
142
- root_cert: Certificate,
143
- root_key: RSAPrivateKey,
144
- alg: hashes.HashAlgorithm,
143
+ device_public_key: RSAPublicKey,
144
+ root_cert: Certificate,
145
+ root_key: RSAPrivateKey,
146
+ alg: hashes.HashAlgorithm,
145
147
  ) -> Certificate:
146
148
  """
147
149
  Build the device certificate (leaf) signed by the root:
@@ -173,9 +175,13 @@ def build_device_certificate(
173
175
  x509.KeyUsage(
174
176
  digital_signature=True,
175
177
  key_encipherment=True,
176
- key_cert_sign=False, crl_sign=False,
177
- content_commitment=False, data_encipherment=False,
178
- key_agreement=False, encipher_only=False, decipher_only=False,
178
+ key_cert_sign=False,
179
+ crl_sign=False,
180
+ content_commitment=False,
181
+ data_encipherment=False,
182
+ key_agreement=False,
183
+ encipher_only=False,
184
+ decipher_only=False,
179
185
  ),
180
186
  critical=True,
181
187
  )
@@ -188,10 +194,11 @@ def build_device_certificate(
188
194
  # Public API for your pairing flow (renamed)
189
195
  # ==========================================
190
196
 
197
+
191
198
  def generate_pairing_cert_chain(
192
- device_public_key_pem: bytes,
193
- private_key: Optional[RSAPrivateKey] = None,
194
- device_version: Union[tuple[int, int, int], str, None] = (4, 0, 0),
199
+ device_public_key_pem: bytes,
200
+ private_key: Optional[RSAPrivateKey] = None,
201
+ device_version: Union[tuple[int, int, int], str, None] = (4, 0, 0),
195
202
  ) -> tuple[bytes, bytes, bytes, bytes, bytes]:
196
203
  """
197
204
  Generate a root→host certificate chain and a device certificate that mirror the
@@ -215,7 +222,7 @@ def generate_pairing_cert_chain(
215
222
  # Device leaf (public key provided by the device)
216
223
  dev_pub = load_pem_public_key(device_public_key_pem)
217
224
  if not isinstance(dev_pub, RSAPublicKey):
218
- raise ValueError("device_public_key_pem must be an RSA PUBLIC KEY in PEM format")
225
+ raise TypeError("device_public_key_pem must be an RSA PUBLIC KEY in PEM format")
219
226
  device_cert = build_device_certificate(dev_pub, root_cert, root_key, alg)
220
227
 
221
228
  return (
@@ -277,6 +284,7 @@ def create_keybag_file(file: Path, common_name: str) -> None:
277
284
  private_key.private_bytes(
278
285
  encoding=serialization.Encoding.PEM,
279
286
  format=PrivateFormat.TraditionalOpenSSL,
280
- encryption_algorithm=serialization.NoEncryption()
281
- ) + cer.public_bytes(encoding=serialization.Encoding.PEM)
287
+ encryption_algorithm=serialization.NoEncryption(),
288
+ )
289
+ + cer.public_bytes(encoding=serialization.Encoding.PEM)
282
290
  )
@@ -12,20 +12,20 @@ def cli() -> None:
12
12
 
13
13
  @cli.group()
14
14
  def activation() -> None:
15
- """ Perform iCloud activation/deactivation or query the current state """
15
+ """Perform iCloud activation/deactivation or query the current state"""
16
16
  pass
17
17
 
18
18
 
19
19
  @activation.command(cls=Command)
20
20
  def state(service_provider: LockdownClient):
21
- """ Get current activation state """
21
+ """Get current activation state"""
22
22
  print(MobileActivationService(service_provider).state)
23
23
 
24
24
 
25
25
  @activation.command(cls=Command)
26
- @click.option('--now', is_flag=True, help='do not wait for next nonce cycle')
26
+ @click.option("--now", is_flag=True, help="do not wait for next nonce cycle")
27
27
  def activate(service_provider: LockdownClient, now):
28
- """ Activate device """
28
+ """Activate device"""
29
29
  activation_service = MobileActivationService(service_provider)
30
30
  if not now:
31
31
  activation_service.wait_for_activation_session()
@@ -34,11 +34,11 @@ def activate(service_provider: LockdownClient, now):
34
34
 
35
35
  @activation.command(cls=Command)
36
36
  def deactivate(service_provider: LockdownClient):
37
- """ Deactivate device """
37
+ """Deactivate device"""
38
38
  MobileActivationService(service_provider).deactivate()
39
39
 
40
40
 
41
41
  @activation.command(cls=Command)
42
42
  def itunes(service_provider: LockdownClient):
43
- """ Tell the device that it has been connected to iTunes (useful for < iOS 4) """
44
- service_provider.set_value(True, key='iTunesHasConnected')
43
+ """Tell the device that it has been connected to iTunes (useful for < iOS 4)"""
44
+ service_provider.set_value(True, key="iTunesHasConnected")
@@ -13,44 +13,44 @@ def cli() -> None:
13
13
 
14
14
  @cli.group()
15
15
  def afc() -> None:
16
- """ Manage device multimedia files """
16
+ """Manage device multimedia files"""
17
17
  pass
18
18
 
19
19
 
20
- @afc.command('shell', cls=Command)
20
+ @afc.command("shell", cls=Command)
21
21
  def afc_shell(service_provider: LockdownClient):
22
- """ open an AFC shell rooted at /var/mobile/Media """
22
+ """open an AFC shell rooted at /var/mobile/Media"""
23
23
  AfcShell.create(service_provider)
24
24
 
25
25
 
26
- @afc.command('pull', cls=Command)
27
- @click.option('-i', '--ignore-errors', is_flag=True, help='Ignore AFC pull errors')
28
- @click.argument('remote_file', type=click.Path(exists=False))
29
- @click.argument('local_file', type=click.Path(exists=False))
26
+ @afc.command("pull", cls=Command)
27
+ @click.option("-i", "--ignore-errors", is_flag=True, help="Ignore AFC pull errors")
28
+ @click.argument("remote_file", type=click.Path(exists=False))
29
+ @click.argument("local_file", type=click.Path(exists=False))
30
30
  def afc_pull(service_provider: LockdownServiceProvider, remote_file: str, local_file: str, ignore_errors: bool) -> None:
31
- """ pull remote file from /var/mobile/Media """
31
+ """pull remote file from /var/mobile/Media"""
32
32
  AfcService(lockdown=service_provider).pull(remote_file, local_file, ignore_errors=ignore_errors)
33
33
 
34
34
 
35
- @afc.command('push', cls=Command)
36
- @click.argument('local_file', type=click.Path(exists=False))
37
- @click.argument('remote_file', type=click.Path(exists=False))
35
+ @afc.command("push", cls=Command)
36
+ @click.argument("local_file", type=click.Path(exists=False))
37
+ @click.argument("remote_file", type=click.Path(exists=False))
38
38
  def afc_push(service_provider: LockdownServiceProvider, local_file: str, remote_file: str) -> None:
39
- """ push local file into /var/mobile/Media """
39
+ """push local file into /var/mobile/Media"""
40
40
  AfcService(lockdown=service_provider).push(local_file, remote_file)
41
41
 
42
42
 
43
- @afc.command('ls', cls=Command)
44
- @click.argument('remote_file', type=click.Path(exists=False))
45
- @click.option('-r', '--recursive', is_flag=True)
43
+ @afc.command("ls", cls=Command)
44
+ @click.argument("remote_file", type=click.Path(exists=False))
45
+ @click.option("-r", "--recursive", is_flag=True)
46
46
  def afc_ls(service_provider: LockdownClient, remote_file, recursive):
47
- """ perform a dirlist rooted at /var/mobile/Media """
47
+ """perform a dirlist rooted at /var/mobile/Media"""
48
48
  for path in AfcService(lockdown=service_provider).dirlist(remote_file, -1 if recursive else 1):
49
49
  print(path)
50
50
 
51
51
 
52
- @afc.command('rm', cls=Command)
53
- @click.argument('remote_file', type=click.Path(exists=False))
52
+ @afc.command("rm", cls=Command)
53
+ @click.argument("remote_file", type=click.Path(exists=False))
54
54
  def afc_rm(service_provider: LockdownClient, remote_file):
55
- """ remove a file rooted at /var/mobile/Media """
55
+ """remove a file rooted at /var/mobile/Media"""
56
56
  AfcService(lockdown=service_provider).rm(remote_file)
@@ -16,23 +16,23 @@ def cli() -> None:
16
16
 
17
17
  @cli.group()
18
18
  def amfi() -> None:
19
- """ Enable developer-mode or query its state """
19
+ """Enable developer-mode or query its state"""
20
20
  pass
21
21
 
22
22
 
23
23
  @amfi.command(cls=Command)
24
24
  def reveal_developer_mode(service_provider: LockdownClient):
25
- """ reveal developer mode option in device's UI """
25
+ """reveal developer mode option in device's UI"""
26
26
  AmfiService(service_provider).reveal_developer_mode_option_in_ui()
27
27
 
28
28
 
29
29
  @amfi.command(cls=Command)
30
30
  def enable_developer_mode(service_provider: LockdownClient):
31
- """ enable developer mode """
31
+ """enable developer mode"""
32
32
  AmfiService(service_provider).enable_developer_mode()
33
33
 
34
34
 
35
35
  @amfi.command(cls=Command)
36
36
  def developer_mode_status(service_provider: LockdownClient):
37
- """ query developer mode status """
37
+ """query developer mode status"""
38
38
  print_json(service_provider.developer_mode_status)
@@ -14,73 +14,85 @@ def cli() -> None:
14
14
 
15
15
  @cli.group()
16
16
  def apps() -> None:
17
- """ Manage installed applications """
17
+ """Manage installed applications"""
18
18
  pass
19
19
 
20
20
 
21
- @apps.command('list', cls=Command)
22
- @click.option('app_type', '-t', '--type', type=click.Choice(['System', 'User', 'Hidden', 'Any']), default='Any',
23
- help='include only applications of given type')
24
- @click.option('--calculate-sizes/--no-calculate-size', default=False)
21
+ @apps.command("list", cls=Command)
22
+ @click.option(
23
+ "app_type",
24
+ "-t",
25
+ "--type",
26
+ type=click.Choice(["System", "User", "Hidden", "Any"]),
27
+ default="Any",
28
+ help="include only applications of given type",
29
+ )
30
+ @click.option("--calculate-sizes/--no-calculate-size", default=False)
25
31
  def apps_list(service_provider: LockdownServiceProvider, app_type: str, calculate_sizes: bool) -> None:
26
- """ list installed apps """
27
- print_json(InstallationProxyService(lockdown=service_provider).get_apps(application_type=app_type,
28
- calculate_sizes=calculate_sizes))
32
+ """list installed apps"""
33
+ print_json(
34
+ InstallationProxyService(lockdown=service_provider).get_apps(
35
+ application_type=app_type, calculate_sizes=calculate_sizes
36
+ )
37
+ )
29
38
 
30
39
 
31
- @apps.command('query', cls=Command)
32
- @click.argument('bundle_identifiers', nargs=-1)
33
- @click.option('--calculate-sizes/--no-calculate-size', default=False)
40
+ @apps.command("query", cls=Command)
41
+ @click.argument("bundle_identifiers", nargs=-1)
42
+ @click.option("--calculate-sizes/--no-calculate-size", default=False)
34
43
  def apps_query(service_provider: LockdownServiceProvider, bundle_identifiers: list[str], calculate_sizes: bool) -> None:
35
- """ query installed apps """
36
- print_json(InstallationProxyService(lockdown=service_provider)
37
- .get_apps(calculate_sizes=calculate_sizes, bundle_identifiers=bundle_identifiers))
44
+ """query installed apps"""
45
+ print_json(
46
+ InstallationProxyService(lockdown=service_provider).get_apps(
47
+ calculate_sizes=calculate_sizes, bundle_identifiers=bundle_identifiers
48
+ )
49
+ )
38
50
 
39
51
 
40
- @apps.command('uninstall', cls=Command)
41
- @click.argument('bundle_id')
52
+ @apps.command("uninstall", cls=Command)
53
+ @click.argument("bundle_id")
42
54
  def uninstall(service_provider: LockdownClient, bundle_id):
43
- """ uninstall app by given bundle_id """
55
+ """uninstall app by given bundle_id"""
44
56
  InstallationProxyService(lockdown=service_provider).uninstall(bundle_id)
45
57
 
46
58
 
47
- @apps.command('install', cls=Command)
48
- @click.option('--developer', is_flag=True, help='Install developer package')
49
- @click.argument('package', type=click.Path(exists=True))
59
+ @apps.command("install", cls=Command)
60
+ @click.option("--developer", is_flag=True, help="Install developer package")
61
+ @click.argument("package", type=click.Path(exists=True))
50
62
  def install(service_provider: LockdownServiceProvider, package: str, developer: bool) -> None:
51
- """ install given .ipa/.app/.ipcc """
63
+ """install given .ipa/.app/.ipcc"""
52
64
  InstallationProxyService(lockdown=service_provider).install_from_local(package, developer=developer)
53
65
 
54
66
 
55
- @apps.command('afc', cls=Command)
56
- @click.option('--documents', is_flag=True)
57
- @click.argument('bundle_id')
67
+ @apps.command("afc", cls=Command)
68
+ @click.option("--documents", is_flag=True)
69
+ @click.argument("bundle_id")
58
70
  def afc(service_provider: LockdownClient, bundle_id: str, documents: bool):
59
- """ open an AFC shell for given bundle_id, assuming its profile is installed """
71
+ """open an AFC shell for given bundle_id, assuming its profile is installed"""
60
72
  HouseArrestService(lockdown=service_provider, bundle_id=bundle_id, documents_only=documents).shell()
61
73
 
62
74
 
63
- @apps.command('pull', cls=Command)
64
- @click.argument('bundle_id')
65
- @click.argument('remote_file', type=click.Path(exists=False))
66
- @click.argument('local_file', type=click.Path(exists=False))
75
+ @apps.command("pull", cls=Command)
76
+ @click.argument("bundle_id")
77
+ @click.argument("remote_file", type=click.Path(exists=False))
78
+ @click.argument("local_file", type=click.Path(exists=False))
67
79
  def pull(service_provider: LockdownClient, bundle_id: str, remote_file: str, local_file: str):
68
- """ pull remote file from specified bundle_id """
80
+ """pull remote file from specified bundle_id"""
69
81
  HouseArrestService(lockdown=service_provider, bundle_id=bundle_id).pull(remote_file, local_file)
70
82
 
71
83
 
72
- @apps.command('push', cls=Command)
73
- @click.argument('bundle_id')
74
- @click.argument('local_file', type=click.Path(exists=False))
75
- @click.argument('remote_file', type=click.Path(exists=False))
84
+ @apps.command("push", cls=Command)
85
+ @click.argument("bundle_id")
86
+ @click.argument("local_file", type=click.Path(exists=False))
87
+ @click.argument("remote_file", type=click.Path(exists=False))
76
88
  def push(service_provider: LockdownClient, bundle_id: str, local_file: str, remote_file: str):
77
- """ push local file into specified bundle_id """
89
+ """push local file into specified bundle_id"""
78
90
  HouseArrestService(lockdown=service_provider, bundle_id=bundle_id).push(local_file, remote_file)
79
91
 
80
92
 
81
- @apps.command('rm', cls=Command)
82
- @click.argument('bundle_id')
83
- @click.argument('remote_file', type=click.Path(exists=False))
93
+ @apps.command("rm", cls=Command)
94
+ @click.argument("bundle_id")
95
+ @click.argument("remote_file", type=click.Path(exists=False))
84
96
  def rm(service_provider: LockdownClient, bundle_id: str, remote_file: str):
85
- """ remove remote file from specified bundle_id """
97
+ """remove remote file from specified bundle_id"""
86
98
  HouseArrestService(lockdown=service_provider, bundle_id=bundle_id).rm(remote_file)