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/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
|
-
|
|
18
|
+
cli = InjectingTyper(
|
|
19
|
+
name="profile",
|
|
20
|
+
help="Manage installed profiles or install SSL certificates",
|
|
21
|
+
no_args_is_help=True,
|
|
22
|
+
)
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
@cli.
|
|
25
|
-
def
|
|
26
|
-
"""
|
|
27
|
-
pass
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@profile_group.command('list', cls=Command)
|
|
31
|
-
def profile_list(service_provider: LockdownClient):
|
|
32
|
-
""" List installed profiles """
|
|
25
|
+
@cli.command("list")
|
|
26
|
+
def profile_list(service_provider: ServiceProviderDep) -> None:
|
|
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,101 +48,129 @@ 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
|
|
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
|
-
|
|
57
|
-
""" Get/Set cloud configuration """
|
|
58
|
+
@cli.command("cloud-configuration")
|
|
59
|
+
def profile_cloud_configuration(service_provider: ServiceProviderDep, config: Optional[Path] = None) -> None:
|
|
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
|
-
|
|
62
|
-
|
|
64
|
+
with config.open("rb") as config_file:
|
|
65
|
+
config_json = plistlib.load(config_file)
|
|
66
|
+
logger.info(f"applying cloud configuration {config_json}")
|
|
63
67
|
MobileConfigService(lockdown=service_provider).set_cloud_configuration(config_json)
|
|
64
|
-
logger.info(
|
|
68
|
+
logger.info("applied cloud configuration")
|
|
65
69
|
|
|
66
70
|
|
|
67
|
-
@
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
""" Store a profile """
|
|
71
|
+
@cli.command("store")
|
|
72
|
+
def profile_store(service_provider: ServiceProviderDep, profiles: list[Path]) -> None:
|
|
73
|
+
"""Store a profile"""
|
|
71
74
|
service = MobileConfigService(lockdown=service_provider)
|
|
72
75
|
for profile in profiles:
|
|
73
|
-
logger.info(f
|
|
74
|
-
service.store_profile(profile.
|
|
76
|
+
logger.info(f"storing {profile.name}")
|
|
77
|
+
service.store_profile(profile.read_bytes())
|
|
75
78
|
|
|
76
79
|
|
|
77
|
-
@
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
""" Remove a profile by its name """
|
|
80
|
+
@cli.command("remove")
|
|
81
|
+
def profile_remove(service_provider: ServiceProviderDep, name: str) -> None:
|
|
82
|
+
"""Remove a profile by its name"""
|
|
81
83
|
MobileConfigService(lockdown=service_provider).remove_profile(name)
|
|
82
84
|
|
|
83
85
|
|
|
84
|
-
@
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
@cli.command("set-wifi-power")
|
|
87
|
+
def profile_set_wifi_power(service_provider: ServiceProviderDep, state: Literal["on", "off"] = "off") -> None:
|
|
88
|
+
"""change Wi-Fi power state"""
|
|
89
|
+
MobileConfigService(lockdown=service_provider).set_wifi_power_state(state == "on")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@cli.command("erase-device")
|
|
93
|
+
def profile_erase_device(
|
|
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,
|
|
103
|
+
) -> None:
|
|
104
|
+
"""Erase device"""
|
|
105
|
+
logger.info(
|
|
106
|
+
f"Erasing device with preserve_data_plan: {preserve_data_plan}, "
|
|
107
|
+
f"disallow_proximity_setup: {disallow_proximity_setup}"
|
|
108
|
+
)
|
|
101
109
|
MobileConfigService(lockdown=service_provider).erase_device(preserve_data_plan, disallow_proximity_setup)
|
|
102
|
-
logger.info(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
@
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
"""
|
|
118
|
-
|
|
119
|
-
|
|
110
|
+
logger.info("Erased device")
|
|
111
|
+
|
|
112
|
+
|
|
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:
|
|
125
|
+
"""Create keybag storing certificate and private key"""
|
|
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:
|
|
142
|
+
"""Supervise device"""
|
|
143
|
+
if MobileActivationService(service_provider).state == "Unactivated":
|
|
144
|
+
logger.info("Activating device")
|
|
120
145
|
MobileActivationService(service_provider).activate()
|
|
121
|
-
logger.info(
|
|
122
|
-
logger.info(
|
|
146
|
+
logger.info("Device has been successfully activated")
|
|
147
|
+
logger.info("Supervising device")
|
|
123
148
|
if keybag is None:
|
|
124
149
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
125
|
-
keybag = Path(temp_dir) /
|
|
150
|
+
keybag = Path(temp_dir) / "keybag"
|
|
126
151
|
create_keybag_file(keybag, organization)
|
|
127
152
|
MobileConfigService(lockdown=service_provider).supervise(organization, keybag)
|
|
128
153
|
else:
|
|
129
154
|
MobileConfigService(lockdown=service_provider).supervise(organization, Path(keybag))
|
|
130
155
|
|
|
131
|
-
logger.info(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
@
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
156
|
+
logger.info("Device has been successfully supervised")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@cli.command("install-wifi-profile")
|
|
160
|
+
def profile_install_wifi_profile(
|
|
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,
|
|
173
|
+
) -> None:
|
|
142
174
|
"""
|
|
143
175
|
Install Wi-Fi profile
|
|
144
176
|
|
|
@@ -147,34 +179,58 @@ def profile_install_wifi_profile(service_provider: LockdownServiceProvider, encr
|
|
|
147
179
|
if keybag is not None:
|
|
148
180
|
keybag = Path(keybag)
|
|
149
181
|
MobileConfigService(lockdown=service_provider).install_wifi_profile(
|
|
150
|
-
encryption_type=encryption_type, ssid=ssid, password=password, keybag_file=keybag
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
@
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
182
|
+
encryption_type=encryption_type, ssid=ssid, password=password, keybag_file=keybag
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@cli.command("install-http-proxy")
|
|
187
|
+
def profile_install_http_proxy(
|
|
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,
|
|
202
|
+
) -> None:
|
|
203
|
+
"""Install HTTP Proxy profile"""
|
|
160
204
|
if keybag is not None:
|
|
161
205
|
keybag = Path(keybag)
|
|
162
206
|
MobileConfigService(lockdown=service_provider).install_http_proxy(server, port, keybag_file=keybag)
|
|
163
207
|
|
|
164
208
|
|
|
165
|
-
@
|
|
166
|
-
def profile_remove_http_proxy(service_provider:
|
|
167
|
-
"""
|
|
209
|
+
@cli.command("remove-http-proxy")
|
|
210
|
+
def profile_remove_http_proxy(service_provider: ServiceProviderDep) -> None:
|
|
211
|
+
"""Remove HTTP Proxy profile that was previously installed using pymobiledevice3"""
|
|
168
212
|
MobileConfigService(lockdown=service_provider).remove_http_proxy()
|
|
169
213
|
|
|
170
214
|
|
|
171
|
-
@
|
|
172
|
-
@click.option('--keybag', type=click.Path(file_okay=True, dir_okay=False, exists=True))
|
|
173
|
-
@click.option('--enforced-software-update-delay', type=click.IntRange(0, 90), default=0)
|
|
215
|
+
@cli.command("install-restrictions-profile")
|
|
174
216
|
def profile_install_restrictions_profile(
|
|
175
|
-
|
|
176
|
-
|
|
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,
|
|
230
|
+
) -> None:
|
|
231
|
+
"""Install restrictions profile (can be used for delayed OTA)"""
|
|
177
232
|
if keybag is not None:
|
|
178
233
|
keybag = Path(keybag)
|
|
179
234
|
MobileConfigService(lockdown=service_provider).install_restrictions_profile(
|
|
180
|
-
enforced_software_update_delay=enforced_software_update_delay, keybag_file=keybag
|
|
235
|
+
enforced_software_update_delay=enforced_software_update_delay, keybag_file=keybag
|
|
236
|
+
)
|
pymobiledevice3/cli/provision.py
CHANGED
|
@@ -1,58 +1,59 @@
|
|
|
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
|
-
"""
|
|
21
|
-
|
|
21
|
+
@cli.command("install")
|
|
22
|
+
def provision_install(service_provider: ServiceProviderDep, profile: Path) -> None:
|
|
23
|
+
"""install a provision profile (.mobileprovision file)"""
|
|
24
|
+
with profile.open("rb") as profile_file:
|
|
25
|
+
MisagentService(lockdown=service_provider).install(profile_file)
|
|
22
26
|
|
|
23
27
|
|
|
24
|
-
@
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
""" install a provision profile (.mobileprovision file) """
|
|
28
|
-
MisagentService(lockdown=service_provider).install(profile)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@provision.command('remove', cls=Command)
|
|
32
|
-
@click.argument('profile_id')
|
|
33
|
-
def provision_remove(service_provider: LockdownClient, profile_id):
|
|
34
|
-
""" remove a provision profile """
|
|
28
|
+
@cli.command("remove")
|
|
29
|
+
def provision_remove(service_provider: ServiceProviderDep, profile_id: str) -> None:
|
|
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:
|
|
40
|
-
"""
|
|
34
|
+
@cli.command("clear")
|
|
35
|
+
def provision_clear(service_provider: ServiceProviderDep) -> None:
|
|
36
|
+
"""remove all provision profiles"""
|
|
41
37
|
for profile in MisagentService(lockdown=service_provider).copy_all():
|
|
42
|
-
MisagentService(lockdown=service_provider).remove(profile.plist[
|
|
38
|
+
MisagentService(lockdown=service_provider).remove(profile.plist["UUID"])
|
|
43
39
|
|
|
44
40
|
|
|
45
|
-
@
|
|
46
|
-
def provision_list(service_provider:
|
|
47
|
-
"""
|
|
41
|
+
@cli.command("list")
|
|
42
|
+
def provision_list(service_provider: ServiceProviderDep) -> None:
|
|
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
|
-
|
|
54
|
-
|
|
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:
|
|
55
|
+
"""dump installed provision profiles to specified location"""
|
|
55
56
|
for profile in MisagentService(lockdown=service_provider).copy_all():
|
|
56
|
-
filename = f
|
|
57
|
-
logger.info(f
|
|
57
|
+
filename = f"{profile.plist['UUID']}.mobileprovision"
|
|
58
|
+
logger.info(f"downloading {filename}")
|
|
58
59
|
(Path(out) / filename).write_bytes(profile.buf)
|