pymobiledevice3 6.2.0__py3-none-any.whl → 7.0.0__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.
- pymobiledevice3/__main__.py +136 -44
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/bonjour.py +19 -20
- pymobiledevice3/cli/activation.py +24 -22
- pymobiledevice3/cli/afc.py +49 -41
- pymobiledevice3/cli/amfi.py +13 -18
- pymobiledevice3/cli/apps.py +71 -65
- pymobiledevice3/cli/backup.py +134 -93
- pymobiledevice3/cli/bonjour.py +31 -29
- pymobiledevice3/cli/cli_common.py +179 -232
- pymobiledevice3/cli/companion_proxy.py +12 -12
- pymobiledevice3/cli/crash.py +95 -52
- 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 +387 -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 +18 -22
- pymobiledevice3/cli/lockdown.py +70 -75
- pymobiledevice3/cli/mounter.py +99 -57
- pymobiledevice3/cli/notification.py +38 -26
- pymobiledevice3/cli/pcap.py +36 -20
- pymobiledevice3/cli/power_assertion.py +15 -16
- pymobiledevice3/cli/processes.py +11 -17
- pymobiledevice3/cli/profile.py +120 -75
- pymobiledevice3/cli/provision.py +27 -26
- pymobiledevice3/cli/remote.py +108 -99
- pymobiledevice3/cli/restore.py +134 -129
- pymobiledevice3/cli/springboard.py +50 -50
- pymobiledevice3/cli/syslog.py +138 -74
- pymobiledevice3/cli/usbmux.py +66 -27
- pymobiledevice3/cli/version.py +2 -5
- pymobiledevice3/cli/webinspector.py +149 -103
- pymobiledevice3/remote/remote_service_discovery.py +11 -10
- pymobiledevice3/restore/device.py +28 -4
- pymobiledevice3/service_connection.py +1 -1
- pymobiledevice3/services/mobilebackup2.py +4 -1
- pymobiledevice3/services/screenshot.py +2 -2
- pymobiledevice3/services/web_protocol/automation_session.py +4 -2
- pymobiledevice3/services/web_protocol/cdp_screencast.py +2 -1
- pymobiledevice3/services/web_protocol/element.py +3 -3
- {pymobiledevice3-6.2.0.dist-info → pymobiledevice3-7.0.0.dist-info}/METADATA +3 -2
- {pymobiledevice3-6.2.0.dist-info → pymobiledevice3-7.0.0.dist-info}/RECORD +58 -45
- pymobiledevice3/cli/completions.py +0 -50
- pymobiledevice3/cli/developer.py +0 -1645
- pymobiledevice3/cli/diagnostics.py +0 -110
- {pymobiledevice3-6.2.0.dist-info → pymobiledevice3-7.0.0.dist-info}/WHEEL +0 -0
- {pymobiledevice3-6.2.0.dist-info → pymobiledevice3-7.0.0.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-6.2.0.dist-info → pymobiledevice3-7.0.0.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-6.2.0.dist-info → pymobiledevice3-7.0.0.dist-info}/top_level.txt +0 -0
pymobiledevice3/cli/pcap.py
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
from
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Annotated, Optional
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
+
import typer
|
|
5
6
|
from pygments import formatters, highlight, lexers
|
|
7
|
+
from typer_injector import InjectingTyper
|
|
6
8
|
|
|
7
|
-
from pymobiledevice3.cli.cli_common import
|
|
8
|
-
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
9
|
+
from pymobiledevice3.cli.cli_common import ServiceProviderDep, print_hex, user_requested_colored_output
|
|
9
10
|
from pymobiledevice3.services.pcapd import PcapdService
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
cli = InjectingTyper(
|
|
13
|
+
name="pcap",
|
|
14
|
+
help="Sniff device traffic via pcapd and optionally save to a .pcap file.",
|
|
15
|
+
no_args_is_help=True,
|
|
16
|
+
)
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
def print_packet_header(packet, color: bool) -> None:
|
|
@@ -37,25 +39,39 @@ def print_packet(packet, color: Optional[bool] = None):
|
|
|
37
39
|
return packet
|
|
38
40
|
|
|
39
41
|
|
|
40
|
-
@cli.command(
|
|
41
|
-
@click.argument("out", type=click.File("wb"), required=False)
|
|
42
|
-
@click.option("-c", "--count", type=click.INT, default=-1, help="Number of packets to sniff. Omit to endless sniff.")
|
|
43
|
-
@click.option("--process", default=None, help="Process to filter. Omit for all.")
|
|
44
|
-
@click.option("-i", "--interface", default=None, help="Interface name to filter. Omit for all.")
|
|
42
|
+
@cli.command()
|
|
45
43
|
def pcap(
|
|
46
|
-
service_provider:
|
|
47
|
-
out: Optional[
|
|
48
|
-
count:
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
service_provider: ServiceProviderDep,
|
|
45
|
+
out: Optional[Path] = None,
|
|
46
|
+
count: Annotated[
|
|
47
|
+
int,
|
|
48
|
+
typer.Option(
|
|
49
|
+
"--count",
|
|
50
|
+
"-c",
|
|
51
|
+
help="Number of packets to sniff. Omit to endless sniff.",
|
|
52
|
+
),
|
|
53
|
+
] = -1,
|
|
54
|
+
process: Annotated[
|
|
55
|
+
Optional[str],
|
|
56
|
+
typer.Option(help="Process to filter. Omit for all."),
|
|
57
|
+
] = None,
|
|
58
|
+
interface: Annotated[
|
|
59
|
+
Optional[str],
|
|
60
|
+
typer.Option(
|
|
61
|
+
"--interface",
|
|
62
|
+
"-i",
|
|
63
|
+
help="Interface name to filter. Omit for all.",
|
|
64
|
+
),
|
|
65
|
+
] = None,
|
|
51
66
|
) -> None:
|
|
52
|
-
"""Sniff device traffic"""
|
|
67
|
+
"""Sniff device traffic."""
|
|
53
68
|
service = PcapdService(lockdown=service_provider)
|
|
54
69
|
packets_generator = service.watch(packets_count=count, process=process, interface_name=interface)
|
|
55
70
|
|
|
56
71
|
if out is not None:
|
|
57
72
|
packets_generator_with_print = (print_packet(p) for p in packets_generator)
|
|
58
|
-
|
|
73
|
+
with out.open("wb") as out_file:
|
|
74
|
+
service.write_to_pcap(out_file, packets_generator_with_print)
|
|
59
75
|
return
|
|
60
76
|
|
|
61
77
|
for packet in packets_generator:
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import time
|
|
2
|
+
from typing import Literal, Optional
|
|
2
3
|
|
|
3
|
-
import
|
|
4
|
+
from typer_injector import InjectingTyper
|
|
4
5
|
|
|
5
|
-
from pymobiledevice3.cli.cli_common import
|
|
6
|
-
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
6
|
+
from pymobiledevice3.cli.cli_common import ServiceProviderDep
|
|
7
7
|
from pymobiledevice3.services.power_assertion import PowerAssertionService
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
cli = InjectingTyper(
|
|
10
|
+
name="power-assertion",
|
|
11
|
+
no_args_is_help=True,
|
|
12
|
+
)
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
@cli.command("power-assertion"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def power_assertion(service_provider: LockdownServiceProvider, assertion_type, name, timeout, details) -> None:
|
|
15
|
+
@cli.command("power-assertion")
|
|
16
|
+
def power_assertion(
|
|
17
|
+
service_provider: ServiceProviderDep,
|
|
18
|
+
assertion_type: Literal["AMDPowerAssertionTypeWirelessSync", "PreventUserIdleSystemSleep", "PreventSystemSleep"],
|
|
19
|
+
name: str,
|
|
20
|
+
timeout: int,
|
|
21
|
+
details: Optional[str] = None,
|
|
22
|
+
) -> None:
|
|
24
23
|
"""Create a power assertion"""
|
|
25
24
|
with PowerAssertionService(service_provider).create_power_assertion(assertion_type, name, timeout, details):
|
|
26
25
|
print("> Hit Ctrl+C to exit")
|
pymobiledevice3/cli/processes.py
CHANGED
|
@@ -1,34 +1,28 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from typer_injector import InjectingTyper
|
|
4
4
|
|
|
5
|
-
from pymobiledevice3.cli.cli_common import
|
|
6
|
-
from pymobiledevice3.lockdown import LockdownClient
|
|
5
|
+
from pymobiledevice3.cli.cli_common import ServiceProviderDep, print_json
|
|
7
6
|
from pymobiledevice3.services.os_trace import OsTraceService
|
|
8
7
|
|
|
9
8
|
logger = logging.getLogger(__name__)
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
cli = InjectingTyper(
|
|
12
|
+
name="processes",
|
|
13
|
+
help="View process list using diagnosticsd API",
|
|
14
|
+
no_args_is_help=True,
|
|
15
|
+
)
|
|
15
16
|
|
|
16
17
|
|
|
17
|
-
@cli.
|
|
18
|
-
def
|
|
19
|
-
"""View process list using diagnosticsd API"""
|
|
20
|
-
pass
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@processes.command("ps", cls=Command)
|
|
24
|
-
def processes_ps(service_provider: LockdownClient):
|
|
18
|
+
@cli.command("ps")
|
|
19
|
+
def processes_ps(service_provider: ServiceProviderDep) -> None:
|
|
25
20
|
"""show process list"""
|
|
26
21
|
print_json(OsTraceService(lockdown=service_provider).get_pid_list().get("Payload"))
|
|
27
22
|
|
|
28
23
|
|
|
29
|
-
@
|
|
30
|
-
|
|
31
|
-
def processes_pgrep(service_provider: LockdownClient, expression):
|
|
24
|
+
@cli.command("pgrep")
|
|
25
|
+
def processes_pgrep(service_provider: ServiceProviderDep, expression: str) -> None:
|
|
32
26
|
"""try to match processes pid by given expression (like pgrep)"""
|
|
33
27
|
processes_list = OsTraceService(lockdown=service_provider).get_pid_list().get("Payload")
|
|
34
28
|
for pid, process_info in processes_list.items():
|
pymobiledevice3/cli/profile.py
CHANGED
|
@@ -2,41 +2,45 @@ import logging
|
|
|
2
2
|
import plistlib
|
|
3
3
|
import tempfile
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Annotated, Literal, Optional
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import typer
|
|
8
|
+
from typer_injector import InjectingTyper
|
|
8
9
|
|
|
9
10
|
from pymobiledevice3.ca import create_keybag_file
|
|
10
|
-
from pymobiledevice3.cli.cli_common import
|
|
11
|
-
from pymobiledevice3.lockdown import LockdownClient
|
|
12
|
-
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
11
|
+
from pymobiledevice3.cli.cli_common import ServiceProviderDep, print_json
|
|
13
12
|
from pymobiledevice3.services.mobile_activation import MobileActivationService
|
|
14
13
|
from pymobiledevice3.services.mobile_config import MobileConfigService
|
|
15
14
|
|
|
16
15
|
logger = logging.getLogger(__name__)
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@cli.group("profile")
|
|
25
|
-
def profile_group() -> None:
|
|
26
|
-
"""Managed installed profiles or install SSL certificates"""
|
|
27
|
-
pass
|
|
18
|
+
cli = InjectingTyper(
|
|
19
|
+
name="profile",
|
|
20
|
+
help="Manage installed profiles or install SSL certificates",
|
|
21
|
+
no_args_is_help=True,
|
|
22
|
+
)
|
|
28
23
|
|
|
29
24
|
|
|
30
|
-
@
|
|
31
|
-
def profile_list(service_provider:
|
|
25
|
+
@cli.command("list")
|
|
26
|
+
def profile_list(service_provider: ServiceProviderDep) -> None:
|
|
32
27
|
"""List installed profiles"""
|
|
33
28
|
print_json(MobileConfigService(lockdown=service_provider).get_profile_list())
|
|
34
29
|
|
|
35
30
|
|
|
36
|
-
@
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
@cli.command("install")
|
|
32
|
+
def profile_install(
|
|
33
|
+
service_provider: ServiceProviderDep,
|
|
34
|
+
profiles: list[Path],
|
|
35
|
+
keybag: Annotated[
|
|
36
|
+
Optional[Path],
|
|
37
|
+
typer.Option(
|
|
38
|
+
exists=True,
|
|
39
|
+
file_okay=True,
|
|
40
|
+
dir_okay=False,
|
|
41
|
+
),
|
|
42
|
+
] = None,
|
|
43
|
+
) -> None:
|
|
40
44
|
"""
|
|
41
45
|
Install given profiles
|
|
42
46
|
|
|
@@ -44,61 +48,58 @@ def profile_install(service_provider: LockdownServiceProvider, keybag: Optional[
|
|
|
44
48
|
"""
|
|
45
49
|
service = MobileConfigService(lockdown=service_provider)
|
|
46
50
|
for profile in profiles:
|
|
47
|
-
logger.info(f"installing {profile
|
|
51
|
+
logger.info(f"installing {profile}")
|
|
48
52
|
if keybag is not None:
|
|
49
|
-
service.install_profile_silent(Path(keybag), profile.
|
|
53
|
+
service.install_profile_silent(Path(keybag), profile.read_bytes())
|
|
50
54
|
else:
|
|
51
|
-
service.install_profile(profile.
|
|
55
|
+
service.install_profile(profile.read_bytes())
|
|
52
56
|
|
|
53
57
|
|
|
54
|
-
@
|
|
55
|
-
|
|
56
|
-
def profile_cloud_configuration(service_provider: LockdownServiceProvider, config: Optional[IO]) -> None:
|
|
58
|
+
@cli.command("cloud-configuration")
|
|
59
|
+
def profile_cloud_configuration(service_provider: ServiceProviderDep, config: Optional[Path] = None) -> None:
|
|
57
60
|
"""Get/Set cloud configuration"""
|
|
58
61
|
if not config:
|
|
59
62
|
print_json(MobileConfigService(lockdown=service_provider).get_cloud_configuration())
|
|
60
63
|
else:
|
|
61
|
-
|
|
64
|
+
with config.open("rb") as config_file:
|
|
65
|
+
config_json = plistlib.load(config_file)
|
|
62
66
|
logger.info(f"applying cloud configuration {config_json}")
|
|
63
67
|
MobileConfigService(lockdown=service_provider).set_cloud_configuration(config_json)
|
|
64
68
|
logger.info("applied cloud configuration")
|
|
65
69
|
|
|
66
70
|
|
|
67
|
-
@
|
|
68
|
-
|
|
69
|
-
def profile_store(service_provider: LockdownServiceProvider, profiles: list[IO]) -> None:
|
|
71
|
+
@cli.command("store")
|
|
72
|
+
def profile_store(service_provider: ServiceProviderDep, profiles: list[Path]) -> None:
|
|
70
73
|
"""Store a profile"""
|
|
71
74
|
service = MobileConfigService(lockdown=service_provider)
|
|
72
75
|
for profile in profiles:
|
|
73
76
|
logger.info(f"storing {profile.name}")
|
|
74
|
-
service.store_profile(profile.
|
|
77
|
+
service.store_profile(profile.read_bytes())
|
|
75
78
|
|
|
76
79
|
|
|
77
|
-
@
|
|
78
|
-
|
|
79
|
-
def profile_remove(service_provider: LockdownServiceProvider, name: str) -> None:
|
|
80
|
+
@cli.command("remove")
|
|
81
|
+
def profile_remove(service_provider: ServiceProviderDep, name: str) -> None:
|
|
80
82
|
"""Remove a profile by its name"""
|
|
81
83
|
MobileConfigService(lockdown=service_provider).remove_profile(name)
|
|
82
84
|
|
|
83
85
|
|
|
84
|
-
@
|
|
85
|
-
|
|
86
|
-
def profile_set_wifi_power(service_provider: LockdownServiceProvider, state: str) -> None:
|
|
86
|
+
@cli.command("set-wifi-power")
|
|
87
|
+
def profile_set_wifi_power(service_provider: ServiceProviderDep, state: Literal["on", "off"] = "off") -> None:
|
|
87
88
|
"""change Wi-Fi power state"""
|
|
88
89
|
MobileConfigService(lockdown=service_provider).set_wifi_power_state(state == "on")
|
|
89
90
|
|
|
90
91
|
|
|
91
|
-
@
|
|
92
|
-
@click.option(
|
|
93
|
-
"--preserve-data-plan/--no-preserve-data-plan", default=True, help="Preserves eSIM / data plan after erase"
|
|
94
|
-
)
|
|
95
|
-
@click.option(
|
|
96
|
-
"--disallow-proximity-setup/--no-disallow-proximity-setup",
|
|
97
|
-
default=False,
|
|
98
|
-
help="Disallows to setup the erased device from nearby devices",
|
|
99
|
-
)
|
|
92
|
+
@cli.command("erase-device")
|
|
100
93
|
def profile_erase_device(
|
|
101
|
-
service_provider:
|
|
94
|
+
service_provider: ServiceProviderDep,
|
|
95
|
+
preserve_data_plan: Annotated[
|
|
96
|
+
bool,
|
|
97
|
+
typer.Option(help="Preserves eSIM / data plan after erase"),
|
|
98
|
+
] = True,
|
|
99
|
+
disallow_proximity_setup: Annotated[
|
|
100
|
+
bool,
|
|
101
|
+
typer.Option(help="Disallows setup of the erased device from nearby devices"),
|
|
102
|
+
] = False,
|
|
102
103
|
) -> None:
|
|
103
104
|
"""Erase device"""
|
|
104
105
|
logger.info(
|
|
@@ -109,18 +110,35 @@ def profile_erase_device(
|
|
|
109
110
|
logger.info("Erased device")
|
|
110
111
|
|
|
111
112
|
|
|
112
|
-
@
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
@cli.command("create-keybag")
|
|
114
|
+
def profile_create_keybag(
|
|
115
|
+
keybag: Annotated[
|
|
116
|
+
Path,
|
|
117
|
+
typer.Argument(
|
|
118
|
+
exists=False,
|
|
119
|
+
file_okay=True,
|
|
120
|
+
dir_okay=False,
|
|
121
|
+
),
|
|
122
|
+
],
|
|
123
|
+
organization: str,
|
|
124
|
+
) -> None:
|
|
116
125
|
"""Create keybag storing certificate and private key"""
|
|
117
|
-
create_keybag_file(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
@
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
create_keybag_file(keybag, organization)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@cli.command("supervise")
|
|
130
|
+
def profile_supervise(
|
|
131
|
+
service_provider: ServiceProviderDep,
|
|
132
|
+
organization: str,
|
|
133
|
+
keybag: Annotated[
|
|
134
|
+
Optional[Path],
|
|
135
|
+
typer.Option(
|
|
136
|
+
exists=True,
|
|
137
|
+
file_okay=True,
|
|
138
|
+
dir_okay=False,
|
|
139
|
+
),
|
|
140
|
+
] = None,
|
|
141
|
+
) -> None:
|
|
124
142
|
"""Supervise device"""
|
|
125
143
|
if MobileActivationService(service_provider).state == "Unactivated":
|
|
126
144
|
logger.info("Activating device")
|
|
@@ -138,13 +156,20 @@ def profile_supervise(service_provider: LockdownServiceProvider, organization: s
|
|
|
138
156
|
logger.info("Device has been successfully supervised")
|
|
139
157
|
|
|
140
158
|
|
|
141
|
-
@
|
|
142
|
-
@click.argument("encryption_type")
|
|
143
|
-
@click.argument("ssid")
|
|
144
|
-
@click.argument("password")
|
|
145
|
-
@click.option("--keybag", type=click.Path(file_okay=True, dir_okay=False, exists=True))
|
|
159
|
+
@cli.command("install-wifi-profile")
|
|
146
160
|
def profile_install_wifi_profile(
|
|
147
|
-
service_provider:
|
|
161
|
+
service_provider: ServiceProviderDep,
|
|
162
|
+
encryption_type: str,
|
|
163
|
+
ssid: str,
|
|
164
|
+
password: str,
|
|
165
|
+
keybag: Annotated[
|
|
166
|
+
Optional[Path],
|
|
167
|
+
typer.Option(
|
|
168
|
+
exists=True,
|
|
169
|
+
file_okay=True,
|
|
170
|
+
dir_okay=False,
|
|
171
|
+
),
|
|
172
|
+
] = None,
|
|
148
173
|
) -> None:
|
|
149
174
|
"""
|
|
150
175
|
Install Wi-Fi profile
|
|
@@ -158,12 +183,22 @@ def profile_install_wifi_profile(
|
|
|
158
183
|
)
|
|
159
184
|
|
|
160
185
|
|
|
161
|
-
@
|
|
162
|
-
@click.argument("server")
|
|
163
|
-
@click.argument("port", type=click.IntRange(1, 65535))
|
|
164
|
-
@click.option("--keybag", type=click.Path(file_okay=True, dir_okay=False, exists=True))
|
|
186
|
+
@cli.command("install-http-proxy")
|
|
165
187
|
def profile_install_http_proxy(
|
|
166
|
-
service_provider:
|
|
188
|
+
service_provider: ServiceProviderDep,
|
|
189
|
+
server: str,
|
|
190
|
+
port: Annotated[
|
|
191
|
+
int,
|
|
192
|
+
typer.Argument(min=1, max=0xFFFF),
|
|
193
|
+
],
|
|
194
|
+
keybag: Annotated[
|
|
195
|
+
Optional[Path],
|
|
196
|
+
typer.Option(
|
|
197
|
+
exists=True,
|
|
198
|
+
file_okay=True,
|
|
199
|
+
dir_okay=False,
|
|
200
|
+
),
|
|
201
|
+
] = None,
|
|
167
202
|
) -> None:
|
|
168
203
|
"""Install HTTP Proxy profile"""
|
|
169
204
|
if keybag is not None:
|
|
@@ -171,17 +206,27 @@ def profile_install_http_proxy(
|
|
|
171
206
|
MobileConfigService(lockdown=service_provider).install_http_proxy(server, port, keybag_file=keybag)
|
|
172
207
|
|
|
173
208
|
|
|
174
|
-
@
|
|
175
|
-
def profile_remove_http_proxy(service_provider:
|
|
209
|
+
@cli.command("remove-http-proxy")
|
|
210
|
+
def profile_remove_http_proxy(service_provider: ServiceProviderDep) -> None:
|
|
176
211
|
"""Remove HTTP Proxy profile that was previously installed using pymobiledevice3"""
|
|
177
212
|
MobileConfigService(lockdown=service_provider).remove_http_proxy()
|
|
178
213
|
|
|
179
214
|
|
|
180
|
-
@
|
|
181
|
-
@click.option("--keybag", type=click.Path(file_okay=True, dir_okay=False, exists=True))
|
|
182
|
-
@click.option("--enforced-software-update-delay", type=click.IntRange(0, 90), default=0)
|
|
215
|
+
@cli.command("install-restrictions-profile")
|
|
183
216
|
def profile_install_restrictions_profile(
|
|
184
|
-
service_provider:
|
|
217
|
+
service_provider: ServiceProviderDep,
|
|
218
|
+
keybag: Annotated[
|
|
219
|
+
Optional[Path],
|
|
220
|
+
typer.Option(
|
|
221
|
+
exists=True,
|
|
222
|
+
file_okay=True,
|
|
223
|
+
dir_okay=False,
|
|
224
|
+
),
|
|
225
|
+
] = None,
|
|
226
|
+
enforced_software_update_delay: Annotated[
|
|
227
|
+
int,
|
|
228
|
+
typer.Option(min=0, max=90),
|
|
229
|
+
] = 0,
|
|
185
230
|
) -> None:
|
|
186
231
|
"""Install restrictions profile (can be used for delayed OTA)"""
|
|
187
232
|
if keybag is not None:
|
pymobiledevice3/cli/provision.py
CHANGED
|
@@ -1,56 +1,57 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import Annotated
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
+
import typer
|
|
6
|
+
from typer_injector import InjectingTyper
|
|
5
7
|
|
|
6
|
-
from pymobiledevice3.cli.cli_common import
|
|
7
|
-
from pymobiledevice3.lockdown import LockdownClient
|
|
8
|
+
from pymobiledevice3.cli.cli_common import ServiceProviderDep, print_json
|
|
8
9
|
from pymobiledevice3.services.misagent import MisagentService
|
|
9
10
|
|
|
10
11
|
logger = logging.getLogger(__name__)
|
|
11
12
|
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
cli = InjectingTyper(
|
|
15
|
+
name="provision",
|
|
16
|
+
help="Manage installed provision profiles",
|
|
17
|
+
no_args_is_help=True,
|
|
18
|
+
)
|
|
16
19
|
|
|
17
20
|
|
|
18
|
-
@cli.
|
|
19
|
-
def
|
|
20
|
-
"""Manage installed provision profiles"""
|
|
21
|
-
pass
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@provision.command("install", cls=Command)
|
|
25
|
-
@click.argument("profile", type=click.File("rb"))
|
|
26
|
-
def provision_install(service_provider: LockdownClient, profile):
|
|
21
|
+
@cli.command("install")
|
|
22
|
+
def provision_install(service_provider: ServiceProviderDep, profile: Path) -> None:
|
|
27
23
|
"""install a provision profile (.mobileprovision file)"""
|
|
28
|
-
|
|
24
|
+
with profile.open("rb") as profile_file:
|
|
25
|
+
MisagentService(lockdown=service_provider).install(profile_file)
|
|
29
26
|
|
|
30
27
|
|
|
31
|
-
@
|
|
32
|
-
|
|
33
|
-
def provision_remove(service_provider: LockdownClient, profile_id):
|
|
28
|
+
@cli.command("remove")
|
|
29
|
+
def provision_remove(service_provider: ServiceProviderDep, profile_id: str) -> None:
|
|
34
30
|
"""remove a provision profile"""
|
|
35
31
|
MisagentService(lockdown=service_provider).remove(profile_id)
|
|
36
32
|
|
|
37
33
|
|
|
38
|
-
@
|
|
39
|
-
def provision_clear(service_provider:
|
|
34
|
+
@cli.command("clear")
|
|
35
|
+
def provision_clear(service_provider: ServiceProviderDep) -> None:
|
|
40
36
|
"""remove all provision profiles"""
|
|
41
37
|
for profile in MisagentService(lockdown=service_provider).copy_all():
|
|
42
38
|
MisagentService(lockdown=service_provider).remove(profile.plist["UUID"])
|
|
43
39
|
|
|
44
40
|
|
|
45
|
-
@
|
|
46
|
-
def provision_list(service_provider:
|
|
41
|
+
@cli.command("list")
|
|
42
|
+
def provision_list(service_provider: ServiceProviderDep) -> None:
|
|
47
43
|
"""list installed provision profiles"""
|
|
48
44
|
print_json([p.plist for p in MisagentService(lockdown=service_provider).copy_all()])
|
|
49
45
|
|
|
50
46
|
|
|
51
|
-
@
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
@cli.command("dump")
|
|
48
|
+
def provision_dump(
|
|
49
|
+
service_provider: ServiceProviderDep,
|
|
50
|
+
out: Annotated[
|
|
51
|
+
Path,
|
|
52
|
+
typer.Argument(file_okay=False, dir_okay=True, exists=True),
|
|
53
|
+
],
|
|
54
|
+
) -> None:
|
|
54
55
|
"""dump installed provision profiles to specified location"""
|
|
55
56
|
for profile in MisagentService(lockdown=service_provider).copy_all():
|
|
56
57
|
filename = f"{profile.plist['UUID']}.mobileprovision"
|