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.
- misc/plist_sniffer.py +15 -15
- misc/remotexpc_sniffer.py +29 -28
- misc/understanding_idevice_protocol_layers.md +15 -10
- pymobiledevice3/__main__.py +317 -127
- pymobiledevice3/_version.py +22 -4
- pymobiledevice3/bonjour.py +358 -113
- pymobiledevice3/ca.py +253 -16
- pymobiledevice3/cli/activation.py +31 -23
- pymobiledevice3/cli/afc.py +49 -40
- pymobiledevice3/cli/amfi.py +16 -21
- pymobiledevice3/cli/apps.py +87 -42
- pymobiledevice3/cli/backup.py +160 -90
- pymobiledevice3/cli/bonjour.py +44 -40
- pymobiledevice3/cli/cli_common.py +204 -198
- pymobiledevice3/cli/companion_proxy.py +14 -14
- pymobiledevice3/cli/crash.py +105 -56
- pymobiledevice3/cli/developer/__init__.py +62 -0
- pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
- pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
- pymobiledevice3/cli/developer/arbitration.py +50 -0
- pymobiledevice3/cli/developer/condition.py +33 -0
- pymobiledevice3/cli/developer/core_device.py +294 -0
- pymobiledevice3/cli/developer/debugserver.py +244 -0
- pymobiledevice3/cli/developer/dvt/__init__.py +438 -0
- pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
- pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
- pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
- pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
- pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
- pymobiledevice3/cli/developer/simulate_location.py +51 -0
- pymobiledevice3/cli/diagnostics/__init__.py +75 -0
- pymobiledevice3/cli/diagnostics/battery.py +47 -0
- pymobiledevice3/cli/idam.py +42 -0
- pymobiledevice3/cli/lockdown.py +108 -103
- pymobiledevice3/cli/mounter.py +158 -99
- pymobiledevice3/cli/notification.py +38 -26
- pymobiledevice3/cli/pcap.py +45 -24
- pymobiledevice3/cli/power_assertion.py +18 -17
- pymobiledevice3/cli/processes.py +17 -23
- pymobiledevice3/cli/profile.py +165 -109
- pymobiledevice3/cli/provision.py +35 -34
- pymobiledevice3/cli/remote.py +217 -129
- pymobiledevice3/cli/restore.py +159 -143
- pymobiledevice3/cli/springboard.py +63 -53
- pymobiledevice3/cli/syslog.py +193 -86
- pymobiledevice3/cli/usbmux.py +73 -33
- pymobiledevice3/cli/version.py +5 -7
- pymobiledevice3/cli/webinspector.py +376 -214
- pymobiledevice3/common.py +3 -1
- pymobiledevice3/exceptions.py +182 -58
- pymobiledevice3/irecv.py +52 -53
- pymobiledevice3/irecv_devices.py +1489 -464
- pymobiledevice3/lockdown.py +473 -275
- pymobiledevice3/lockdown_service_provider.py +15 -8
- pymobiledevice3/osu/os_utils.py +27 -9
- pymobiledevice3/osu/posix_util.py +34 -15
- pymobiledevice3/osu/win_util.py +14 -8
- pymobiledevice3/pair_records.py +102 -21
- pymobiledevice3/remote/common.py +8 -4
- pymobiledevice3/remote/core_device/app_service.py +94 -67
- pymobiledevice3/remote/core_device/core_device_service.py +17 -14
- pymobiledevice3/remote/core_device/device_info.py +5 -5
- pymobiledevice3/remote/core_device/diagnostics_service.py +19 -4
- pymobiledevice3/remote/core_device/file_service.py +53 -23
- pymobiledevice3/remote/remote_service_discovery.py +79 -45
- pymobiledevice3/remote/remotexpc.py +73 -44
- pymobiledevice3/remote/tunnel_service.py +442 -317
- pymobiledevice3/remote/utils.py +14 -13
- pymobiledevice3/remote/xpc_message.py +145 -125
- pymobiledevice3/resources/dsc_uuid_map.py +19 -19
- pymobiledevice3/resources/firmware_notifications.py +20 -16
- pymobiledevice3/resources/notifications.txt +144 -0
- pymobiledevice3/restore/asr.py +27 -27
- pymobiledevice3/restore/base_restore.py +110 -21
- pymobiledevice3/restore/consts.py +87 -66
- pymobiledevice3/restore/device.py +59 -12
- pymobiledevice3/restore/fdr.py +46 -48
- pymobiledevice3/restore/ftab.py +19 -19
- pymobiledevice3/restore/img4.py +163 -0
- pymobiledevice3/restore/mbn.py +587 -0
- pymobiledevice3/restore/recovery.py +151 -151
- pymobiledevice3/restore/restore.py +562 -544
- pymobiledevice3/restore/restore_options.py +131 -110
- pymobiledevice3/restore/restored_client.py +51 -31
- pymobiledevice3/restore/tss.py +385 -267
- pymobiledevice3/service_connection.py +252 -59
- pymobiledevice3/services/accessibilityaudit.py +202 -120
- pymobiledevice3/services/afc.py +962 -365
- pymobiledevice3/services/amfi.py +24 -30
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +71 -47
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +101 -79
- pymobiledevice3/services/diagnostics.py +973 -967
- pymobiledevice3/services/dtfetchsymbols.py +8 -8
- pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
- pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
- pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
- pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
- pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
- pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +466 -384
- pymobiledevice3/services/dvt/instruments/device_info.py +20 -11
- pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
- pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
- pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
- pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
- pymobiledevice3/services/dvt/instruments/process_control.py +35 -10
- pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
- pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
- pymobiledevice3/services/dvt/testmanaged/xcuitest.py +42 -52
- pymobiledevice3/services/file_relay.py +10 -10
- pymobiledevice3/services/heartbeat.py +9 -8
- pymobiledevice3/services/house_arrest.py +16 -15
- pymobiledevice3/services/idam.py +20 -0
- pymobiledevice3/services/installation_proxy.py +173 -81
- pymobiledevice3/services/lockdown_service.py +20 -10
- pymobiledevice3/services/misagent.py +22 -19
- pymobiledevice3/services/mobile_activation.py +147 -64
- pymobiledevice3/services/mobile_config.py +331 -294
- pymobiledevice3/services/mobile_image_mounter.py +141 -113
- pymobiledevice3/services/mobilebackup2.py +203 -145
- pymobiledevice3/services/notification_proxy.py +11 -11
- pymobiledevice3/services/os_trace.py +134 -74
- pymobiledevice3/services/pcapd.py +314 -302
- pymobiledevice3/services/power_assertion.py +10 -9
- pymobiledevice3/services/preboard.py +4 -4
- pymobiledevice3/services/remote_fetch_symbols.py +21 -14
- pymobiledevice3/services/remote_server.py +176 -146
- pymobiledevice3/services/restore_service.py +16 -16
- pymobiledevice3/services/screenshot.py +15 -12
- pymobiledevice3/services/simulate_location.py +7 -7
- pymobiledevice3/services/springboard.py +15 -15
- pymobiledevice3/services/syslog.py +5 -5
- pymobiledevice3/services/web_protocol/alert.py +11 -11
- pymobiledevice3/services/web_protocol/automation_session.py +251 -239
- pymobiledevice3/services/web_protocol/cdp_screencast.py +46 -37
- pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
- pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
- pymobiledevice3/services/web_protocol/driver.py +114 -111
- pymobiledevice3/services/web_protocol/element.py +124 -111
- pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
- pymobiledevice3/services/web_protocol/selenium_api.py +49 -49
- pymobiledevice3/services/web_protocol/session_protocol.py +18 -12
- pymobiledevice3/services/web_protocol/switch_to.py +30 -27
- pymobiledevice3/services/webinspector.py +189 -155
- pymobiledevice3/tcp_forwarder.py +87 -69
- pymobiledevice3/tunneld/__init__.py +0 -0
- pymobiledevice3/tunneld/api.py +63 -0
- pymobiledevice3/tunneld/server.py +603 -0
- pymobiledevice3/usbmux.py +198 -147
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/METADATA +55 -28
- pymobiledevice3-7.0.6.dist-info/RECORD +188 -0
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/WHEEL +1 -1
- pymobiledevice3/cli/developer.py +0 -1215
- pymobiledevice3/cli/diagnostics.py +0 -99
- pymobiledevice3/tunneld.py +0 -524
- pymobiledevice3-4.14.6.dist-info/RECORD +0 -168
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info/licenses}/LICENSE +0 -0
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/top_level.txt +0 -0
pymobiledevice3/cli/syslog.py
CHANGED
|
@@ -2,45 +2,48 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
import posixpath
|
|
4
4
|
import re
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from
|
|
5
|
+
from contextlib import nullcontext
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Annotated, Optional, TextIO
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from typer_injector import InjectingTyper
|
|
11
|
+
|
|
12
|
+
from pymobiledevice3.cli.cli_common import (
|
|
13
|
+
ServiceProviderDep,
|
|
14
|
+
get_last_used_terminal_formatting,
|
|
15
|
+
user_requested_colored_output,
|
|
16
|
+
)
|
|
11
17
|
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
12
|
-
from pymobiledevice3.services.os_trace import OsTraceService, SyslogLogLevel
|
|
18
|
+
from pymobiledevice3.services.os_trace import OsTraceService, SyslogEntry, SyslogLogLevel
|
|
13
19
|
from pymobiledevice3.services.syslog import SyslogService
|
|
14
20
|
|
|
15
21
|
logger = logging.getLogger(__name__)
|
|
16
22
|
|
|
23
|
+
cli = InjectingTyper(
|
|
24
|
+
name="syslog",
|
|
25
|
+
help="Watch syslog messages",
|
|
26
|
+
no_args_is_help=True,
|
|
27
|
+
)
|
|
17
28
|
|
|
18
|
-
@click.group()
|
|
19
|
-
def cli() -> None:
|
|
20
|
-
pass
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@cli.group()
|
|
24
|
-
def syslog() -> None:
|
|
25
|
-
""" Watch syslog messages """
|
|
26
|
-
pass
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
""" view live syslog lines in raw bytes form from old relay """
|
|
30
|
+
@cli.command("live-old")
|
|
31
|
+
def syslog_live_old(service_provider: ServiceProviderDep) -> None:
|
|
32
|
+
"""view live syslog lines in raw bytes form from old relay"""
|
|
32
33
|
for line in SyslogService(service_provider=service_provider).watch():
|
|
33
34
|
print(line)
|
|
34
35
|
|
|
35
36
|
|
|
36
|
-
def format_line(
|
|
37
|
+
def format_line(
|
|
38
|
+
color: bool, pid: int, syslog_entry: SyslogEntry, include_label: bool, image_offset: bool = False
|
|
39
|
+
) -> Optional[str]:
|
|
37
40
|
log_level_colors = {
|
|
38
|
-
SyslogLogLevel.NOTICE.name:
|
|
39
|
-
SyslogLogLevel.INFO.name:
|
|
40
|
-
SyslogLogLevel.DEBUG.name:
|
|
41
|
-
SyslogLogLevel.ERROR.name:
|
|
42
|
-
SyslogLogLevel.FAULT.name:
|
|
43
|
-
SyslogLogLevel.USER_ACTION.name:
|
|
41
|
+
SyslogLogLevel.NOTICE.name: "white",
|
|
42
|
+
SyslogLogLevel.INFO.name: "white",
|
|
43
|
+
SyslogLogLevel.DEBUG.name: "green",
|
|
44
|
+
SyslogLogLevel.ERROR.name: "red",
|
|
45
|
+
SyslogLogLevel.FAULT.name: "red",
|
|
46
|
+
SyslogLogLevel.USER_ACTION.name: "white",
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
syslog_pid = syslog_entry.pid
|
|
@@ -50,55 +53,75 @@ def format_line(color, pid, syslog_entry, include_label):
|
|
|
50
53
|
image_name = posixpath.basename(syslog_entry.image_name)
|
|
51
54
|
message = syslog_entry.message
|
|
52
55
|
process_name = posixpath.basename(filename)
|
|
53
|
-
|
|
56
|
+
image_offset_str = f"+0x{syslog_entry.image_offset:x}" if image_offset and image_name else ""
|
|
57
|
+
label = ""
|
|
54
58
|
|
|
55
59
|
if (pid != -1) and (syslog_pid != pid):
|
|
56
60
|
return None
|
|
57
61
|
|
|
58
62
|
if syslog_entry.label is not None:
|
|
59
|
-
label = f
|
|
63
|
+
label = f"[{syslog_entry.label.subsystem}][{syslog_entry.label.category}]"
|
|
60
64
|
|
|
61
65
|
if color:
|
|
62
|
-
timestamp =
|
|
63
|
-
process_name =
|
|
66
|
+
timestamp = typer.style(str(timestamp), "green")
|
|
67
|
+
process_name = typer.style(process_name, "magenta")
|
|
64
68
|
if len(image_name) > 0:
|
|
65
|
-
image_name =
|
|
66
|
-
|
|
69
|
+
image_name = typer.style(image_name, "magenta")
|
|
70
|
+
if image_offset:
|
|
71
|
+
image_offset_str = typer.style(image_offset_str, "blue")
|
|
72
|
+
syslog_pid = typer.style(syslog_pid, "cyan")
|
|
67
73
|
log_level_color = log_level_colors[level]
|
|
68
|
-
level =
|
|
69
|
-
label =
|
|
70
|
-
message =
|
|
74
|
+
level = typer.style(level, log_level_color)
|
|
75
|
+
label = typer.style(label, "cyan")
|
|
76
|
+
message = typer.style(message, log_level_color)
|
|
71
77
|
|
|
72
|
-
line_format =
|
|
78
|
+
line_format = "{timestamp} {process_name}{{{image_name}{image_offset_str}}}[{pid}] <{level}>: {message}"
|
|
73
79
|
|
|
74
80
|
if include_label:
|
|
75
|
-
line_format += f
|
|
76
|
-
|
|
77
|
-
line = line_format.format(
|
|
78
|
-
|
|
81
|
+
line_format += f" {label}"
|
|
82
|
+
|
|
83
|
+
line = line_format.format(
|
|
84
|
+
timestamp=timestamp,
|
|
85
|
+
process_name=process_name,
|
|
86
|
+
image_name=image_name,
|
|
87
|
+
pid=syslog_pid,
|
|
88
|
+
level=level,
|
|
89
|
+
message=message,
|
|
90
|
+
image_offset_str=image_offset_str,
|
|
91
|
+
)
|
|
79
92
|
|
|
80
93
|
return line
|
|
81
94
|
|
|
82
95
|
|
|
83
96
|
def syslog_live(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
service_provider: LockdownServiceProvider,
|
|
98
|
+
out: Optional[TextIO],
|
|
99
|
+
pid: int,
|
|
100
|
+
process_name: Optional[str],
|
|
101
|
+
match: list[str],
|
|
102
|
+
match_insensitive: list[str],
|
|
103
|
+
include_label: bool,
|
|
104
|
+
regex: list[str],
|
|
105
|
+
insensitive_regex: list[str],
|
|
106
|
+
image_offset: bool = False,
|
|
107
|
+
) -> None:
|
|
108
|
+
match_regex = [re.compile(f".*({r}).*", re.DOTALL) for r in regex]
|
|
109
|
+
match_regex += [re.compile(f".*({r}).*", re.IGNORECASE | re.DOTALL) for r in insensitive_regex]
|
|
89
110
|
|
|
90
111
|
def replace(m):
|
|
91
|
-
if len(m.groups()):
|
|
92
|
-
return line.replace(m.group(1),
|
|
93
|
-
return
|
|
112
|
+
if len(m.groups()) and line:
|
|
113
|
+
return line.replace(m.group(1), typer.style(m.group(1), bold=True, underline=True))
|
|
114
|
+
return ""
|
|
94
115
|
|
|
95
116
|
for syslog_entry in OsTraceService(lockdown=service_provider).syslog(pid=pid):
|
|
96
|
-
if process_name:
|
|
97
|
-
|
|
98
|
-
|
|
117
|
+
if process_name and posixpath.basename(syslog_entry.filename) != process_name:
|
|
118
|
+
continue
|
|
119
|
+
|
|
120
|
+
line_no_style = format_line(False, pid, syslog_entry, include_label, image_offset)
|
|
121
|
+
line = format_line(user_requested_colored_output(), pid, syslog_entry, include_label, image_offset)
|
|
99
122
|
|
|
100
|
-
line_no_style
|
|
101
|
-
|
|
123
|
+
if line_no_style is None or line is None:
|
|
124
|
+
continue
|
|
102
125
|
|
|
103
126
|
skip = False
|
|
104
127
|
|
|
@@ -110,7 +133,7 @@ def syslog_live(
|
|
|
110
133
|
break
|
|
111
134
|
else:
|
|
112
135
|
if user_requested_colored_output():
|
|
113
|
-
match_line = match_line.replace(m,
|
|
136
|
+
match_line = match_line.replace(m, typer.style(m, bold=True, underline=True))
|
|
114
137
|
line = match_line
|
|
115
138
|
|
|
116
139
|
if match_insensitive is not None:
|
|
@@ -124,8 +147,12 @@ def syslog_live(
|
|
|
124
147
|
start = line.lower().index(m)
|
|
125
148
|
end = start + len(m)
|
|
126
149
|
last_color_formatting = get_last_used_terminal_formatting(line[:start])
|
|
127
|
-
line =
|
|
128
|
-
|
|
150
|
+
line = (
|
|
151
|
+
line[:start]
|
|
152
|
+
+ typer.style(line[start:end], bold=True, underline=True)
|
|
153
|
+
+ last_color_formatting
|
|
154
|
+
+ line[end:]
|
|
155
|
+
)
|
|
129
156
|
|
|
130
157
|
if match_regex:
|
|
131
158
|
skip = True
|
|
@@ -147,31 +174,108 @@ def syslog_live(
|
|
|
147
174
|
print(line_no_style, file=out, flush=True)
|
|
148
175
|
|
|
149
176
|
|
|
150
|
-
@
|
|
151
|
-
@click.option('-o', '--out', type=click.File('wt'), help='log file')
|
|
152
|
-
@click.option('--pid', type=click.INT, default=-1, help='pid to filter. -1 for all')
|
|
153
|
-
@click.option('-pn', '--process-name', help='process name to filter')
|
|
154
|
-
@click.option('-m', '--match', multiple=True, help='match expression')
|
|
155
|
-
@click.option('-mi', '--match-insensitive', multiple=True, help='insensitive match expression')
|
|
156
|
-
@click.option('include_label', '--label', is_flag=True, help='should include label')
|
|
157
|
-
@click.option('-e', '--regex', multiple=True, help='filter only lines matching given regex')
|
|
158
|
-
@click.option('-ei', '--insensitive-regex', multiple=True, help='filter only lines matching given regex (insensitive)')
|
|
177
|
+
@cli.command("live")
|
|
159
178
|
def cli_syslog_live(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
179
|
+
service_provider: ServiceProviderDep,
|
|
180
|
+
out: Annotated[
|
|
181
|
+
Optional[Path],
|
|
182
|
+
typer.Option(
|
|
183
|
+
"--out",
|
|
184
|
+
"-o",
|
|
185
|
+
help="log file",
|
|
186
|
+
),
|
|
187
|
+
] = None,
|
|
188
|
+
pid: Annotated[
|
|
189
|
+
int,
|
|
190
|
+
typer.Option(help="pid to filter. -1 for all"),
|
|
191
|
+
] = -1,
|
|
192
|
+
process_name: Annotated[
|
|
193
|
+
Optional[str],
|
|
194
|
+
typer.Option(
|
|
195
|
+
"--process-name",
|
|
196
|
+
"-pn",
|
|
197
|
+
help="process name to filter",
|
|
198
|
+
),
|
|
199
|
+
] = None,
|
|
200
|
+
match: Annotated[
|
|
201
|
+
Optional[list[str]],
|
|
202
|
+
typer.Option(
|
|
203
|
+
"--match",
|
|
204
|
+
"-m",
|
|
205
|
+
help="match expression",
|
|
206
|
+
),
|
|
207
|
+
] = None,
|
|
208
|
+
match_insensitive: Annotated[
|
|
209
|
+
Optional[list[str]],
|
|
210
|
+
typer.Option(
|
|
211
|
+
"--match-insensitive",
|
|
212
|
+
"-mi",
|
|
213
|
+
help="case-insensitive match expression",
|
|
214
|
+
),
|
|
215
|
+
] = None,
|
|
216
|
+
include_label: Annotated[
|
|
217
|
+
bool,
|
|
218
|
+
typer.Option(
|
|
219
|
+
"--label",
|
|
220
|
+
help="should include label",
|
|
221
|
+
),
|
|
222
|
+
] = False,
|
|
223
|
+
regex: Annotated[
|
|
224
|
+
Optional[list[str]],
|
|
225
|
+
typer.Option(
|
|
226
|
+
"--regex",
|
|
227
|
+
"-e",
|
|
228
|
+
help="filter only lines matching given regex",
|
|
229
|
+
),
|
|
230
|
+
] = None,
|
|
231
|
+
insensitive_regex: Annotated[
|
|
232
|
+
Optional[list[str]],
|
|
233
|
+
typer.Option(
|
|
234
|
+
"--insensitive-regex",
|
|
235
|
+
"-ei",
|
|
236
|
+
help="filter only lines matching given regex (insensitive)",
|
|
237
|
+
),
|
|
238
|
+
] = None,
|
|
239
|
+
image_offset: Annotated[
|
|
240
|
+
bool,
|
|
241
|
+
typer.Option(
|
|
242
|
+
"--image-offset",
|
|
243
|
+
"-io",
|
|
244
|
+
help="Include image offset in log line",
|
|
245
|
+
),
|
|
246
|
+
] = False,
|
|
247
|
+
) -> None:
|
|
248
|
+
"""view live syslog lines"""
|
|
249
|
+
|
|
250
|
+
with out.open("wt") if out else nullcontext() as out_file:
|
|
251
|
+
syslog_live(
|
|
252
|
+
service_provider,
|
|
253
|
+
out_file,
|
|
254
|
+
pid,
|
|
255
|
+
process_name,
|
|
256
|
+
match or [],
|
|
257
|
+
match_insensitive or [],
|
|
258
|
+
include_label,
|
|
259
|
+
regex or [],
|
|
260
|
+
insensitive_regex or [],
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@cli.command("collect")
|
|
265
|
+
def syslog_collect(
|
|
266
|
+
service_provider: ServiceProviderDep,
|
|
267
|
+
out: Annotated[
|
|
268
|
+
Path,
|
|
269
|
+
typer.Argument(
|
|
270
|
+
exists=False,
|
|
271
|
+
dir_okay=True,
|
|
272
|
+
file_okay=False,
|
|
273
|
+
),
|
|
274
|
+
],
|
|
275
|
+
size_limit: int,
|
|
276
|
+
age_limit: int,
|
|
277
|
+
start_time: int,
|
|
278
|
+
) -> None:
|
|
175
279
|
"""
|
|
176
280
|
Collect the system logs into a .logarchive that can be viewed later with tools such as log or Console.
|
|
177
281
|
If the filename doesn't exist, system_logs.logarchive will be created in the given directory.
|
|
@@ -179,9 +283,12 @@ def syslog_collect(service_provider: LockdownClient, out, size_limit, age_limit,
|
|
|
179
283
|
if not os.path.exists(out):
|
|
180
284
|
os.makedirs(out)
|
|
181
285
|
|
|
182
|
-
if
|
|
183
|
-
logger.warning(
|
|
184
|
-
|
|
286
|
+
if out.suffix != ".logarchive":
|
|
287
|
+
logger.warning(
|
|
288
|
+
"given out path doesn't end with a .logarchive - consider renaming to be able to view "
|
|
289
|
+
"the file with the likes of the Console.app and the `log show` utilities"
|
|
290
|
+
)
|
|
185
291
|
|
|
186
|
-
OsTraceService(lockdown=service_provider).collect(
|
|
187
|
-
|
|
292
|
+
OsTraceService(lockdown=service_provider).collect(
|
|
293
|
+
str(out), size_limit=size_limit, age_limit=age_limit, start_time=start_time
|
|
294
|
+
)
|
pymobiledevice3/cli/usbmux.py
CHANGED
|
@@ -1,56 +1,95 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import tempfile
|
|
3
|
+
from typing import Annotated, Optional
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
+
import typer
|
|
6
|
+
from typer_injector import InjectingTyper
|
|
5
7
|
|
|
6
8
|
from pymobiledevice3 import usbmux
|
|
7
|
-
from pymobiledevice3.cli.cli_common import USBMUX_OPTION_HELP,
|
|
9
|
+
from pymobiledevice3.cli.cli_common import USBMUX_OPTION_HELP, print_json
|
|
8
10
|
from pymobiledevice3.lockdown import create_using_usbmux
|
|
9
11
|
from pymobiledevice3.tcp_forwarder import UsbmuxTcpForwarder
|
|
10
12
|
|
|
11
13
|
logger = logging.getLogger(__name__)
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
cli = InjectingTyper(
|
|
17
|
+
name="usbmux",
|
|
18
|
+
help="Inspect usbmuxd-connected devices and forward TCP ports to them.",
|
|
19
|
+
no_args_is_help=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@cli.command("forward")
|
|
24
|
+
def usbmux_forward(
|
|
25
|
+
src_port: Annotated[
|
|
26
|
+
int,
|
|
27
|
+
typer.Argument(min=1, max=0xFFFF),
|
|
28
|
+
],
|
|
29
|
+
dst_port: Annotated[
|
|
30
|
+
int,
|
|
31
|
+
typer.Argument(min=1, max=0xFFFF),
|
|
32
|
+
],
|
|
33
|
+
*,
|
|
34
|
+
usbmux_address: Annotated[
|
|
35
|
+
Optional[str],
|
|
36
|
+
typer.Option(
|
|
37
|
+
"--usbmux",
|
|
38
|
+
help=USBMUX_OPTION_HELP,
|
|
39
|
+
),
|
|
40
|
+
] = None,
|
|
41
|
+
serial: Annotated[
|
|
42
|
+
str,
|
|
43
|
+
typer.Option(help="Device serial/UDID to forward traffic to."),
|
|
44
|
+
],
|
|
45
|
+
daemonize: Annotated[
|
|
46
|
+
bool,
|
|
47
|
+
typer.Option("--daemonize", "-d", help="Run the forwarder in the background."),
|
|
48
|
+
] = False,
|
|
49
|
+
) -> None:
|
|
50
|
+
"""Forward a local TCP port to the device via usbmuxd."""
|
|
33
51
|
forwarder = UsbmuxTcpForwarder(serial, dst_port, src_port, usbmux_address=usbmux_address)
|
|
34
52
|
|
|
35
53
|
if daemonize:
|
|
36
54
|
try:
|
|
37
55
|
from daemonize import Daemonize
|
|
38
|
-
except ImportError:
|
|
39
|
-
raise NotImplementedError(
|
|
56
|
+
except ImportError as e:
|
|
57
|
+
raise NotImplementedError("daemonizing is only supported on unix platforms") from e
|
|
40
58
|
|
|
41
|
-
with tempfile.NamedTemporaryFile(
|
|
42
|
-
daemon = Daemonize(app=f
|
|
59
|
+
with tempfile.NamedTemporaryFile("wt") as pid_file:
|
|
60
|
+
daemon = Daemonize(app=f"forwarder {src_port}->{dst_port}", pid=pid_file.name, action=forwarder.start)
|
|
43
61
|
daemon.start()
|
|
44
62
|
else:
|
|
45
63
|
forwarder.start()
|
|
46
64
|
|
|
47
65
|
|
|
48
|
-
@
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
@cli.command("list")
|
|
67
|
+
def usbmux_list(
|
|
68
|
+
usbmux_address: Annotated[
|
|
69
|
+
Optional[str],
|
|
70
|
+
typer.Option(
|
|
71
|
+
"--usbmux",
|
|
72
|
+
help=USBMUX_OPTION_HELP,
|
|
73
|
+
),
|
|
74
|
+
] = None,
|
|
75
|
+
usb: Annotated[
|
|
76
|
+
bool,
|
|
77
|
+
typer.Option(
|
|
78
|
+
"--usb",
|
|
79
|
+
"-u",
|
|
80
|
+
help="show only USB devices",
|
|
81
|
+
),
|
|
82
|
+
] = False,
|
|
83
|
+
network: Annotated[
|
|
84
|
+
bool,
|
|
85
|
+
typer.Option(
|
|
86
|
+
"--network",
|
|
87
|
+
"-n",
|
|
88
|
+
help="show only network devices",
|
|
89
|
+
),
|
|
90
|
+
] = False,
|
|
91
|
+
) -> None:
|
|
92
|
+
"""List devices known to usbmuxd (USB and Wi-Fi)."""
|
|
54
93
|
connected_devices = []
|
|
55
94
|
for device in usbmux.list_devices(usbmux_address=usbmux_address):
|
|
56
95
|
udid = device.serial
|
|
@@ -61,8 +100,9 @@ def usbmux_list(usbmux_address: str, usb: bool, network: bool) -> None:
|
|
|
61
100
|
if network and not device.is_network:
|
|
62
101
|
continue
|
|
63
102
|
|
|
64
|
-
lockdown = create_using_usbmux(
|
|
65
|
-
|
|
103
|
+
lockdown = create_using_usbmux(
|
|
104
|
+
udid, autopair=False, connection_type=device.connection_type, usbmux_address=usbmux_address
|
|
105
|
+
)
|
|
66
106
|
connected_devices.append(lockdown.short_info)
|
|
67
107
|
|
|
68
108
|
print_json(connected_devices)
|
pymobiledevice3/cli/version.py
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
from typer import Typer
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
@click.group()
|
|
5
|
-
def cli() -> None:
|
|
6
|
-
pass
|
|
3
|
+
cli = Typer()
|
|
7
4
|
|
|
8
5
|
|
|
9
6
|
@cli.command()
|
|
10
7
|
def version() -> None:
|
|
11
|
-
"""
|
|
8
|
+
"""Query pymobiledevice3 version"""
|
|
12
9
|
try:
|
|
13
10
|
from pymobiledevice3._version import __version__
|
|
11
|
+
|
|
14
12
|
print(__version__)
|
|
15
13
|
except ImportError:
|
|
16
|
-
print(
|
|
14
|
+
print("version could not be determined. please first install/build the package")
|