pymobiledevice3 5.0.0__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.
- misc/plist_sniffer.py +15 -15
- misc/remotexpc_sniffer.py +29 -28
- pymobiledevice3/__main__.py +128 -102
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/bonjour.py +26 -49
- pymobiledevice3/ca.py +32 -24
- pymobiledevice3/cli/activation.py +7 -7
- pymobiledevice3/cli/afc.py +19 -19
- pymobiledevice3/cli/amfi.py +4 -4
- pymobiledevice3/cli/apps.py +51 -39
- pymobiledevice3/cli/backup.py +58 -32
- pymobiledevice3/cli/bonjour.py +25 -18
- pymobiledevice3/cli/cli_common.py +112 -81
- pymobiledevice3/cli/companion_proxy.py +4 -4
- pymobiledevice3/cli/completions.py +10 -10
- pymobiledevice3/cli/crash.py +37 -31
- pymobiledevice3/cli/developer.py +602 -520
- pymobiledevice3/cli/diagnostics.py +38 -33
- pymobiledevice3/cli/lockdown.py +79 -74
- pymobiledevice3/cli/mounter.py +85 -68
- pymobiledevice3/cli/notification.py +10 -10
- pymobiledevice3/cli/pcap.py +19 -14
- pymobiledevice3/cli/power_assertion.py +12 -10
- pymobiledevice3/cli/processes.py +10 -10
- pymobiledevice3/cli/profile.py +88 -77
- pymobiledevice3/cli/provision.py +17 -17
- pymobiledevice3/cli/remote.py +186 -110
- pymobiledevice3/cli/restore.py +43 -40
- pymobiledevice3/cli/springboard.py +30 -28
- pymobiledevice3/cli/syslog.py +85 -58
- pymobiledevice3/cli/usbmux.py +21 -20
- pymobiledevice3/cli/version.py +3 -2
- pymobiledevice3/cli/webinspector.py +157 -79
- pymobiledevice3/common.py +1 -1
- pymobiledevice3/exceptions.py +154 -60
- pymobiledevice3/irecv.py +49 -53
- pymobiledevice3/irecv_devices.py +1489 -492
- pymobiledevice3/lockdown.py +394 -241
- pymobiledevice3/lockdown_service_provider.py +5 -7
- pymobiledevice3/osu/os_utils.py +18 -9
- pymobiledevice3/osu/posix_util.py +28 -15
- pymobiledevice3/osu/win_util.py +14 -8
- pymobiledevice3/pair_records.py +19 -19
- pymobiledevice3/remote/common.py +4 -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 +10 -8
- pymobiledevice3/remote/core_device/file_service.py +47 -33
- pymobiledevice3/remote/remote_service_discovery.py +53 -35
- pymobiledevice3/remote/remotexpc.py +62 -41
- pymobiledevice3/remote/tunnel_service.py +371 -293
- pymobiledevice3/remote/utils.py +12 -11
- pymobiledevice3/remote/xpc_message.py +145 -125
- pymobiledevice3/resources/dsc_uuid_map.py +19 -19
- pymobiledevice3/resources/firmware_notifications.py +16 -16
- pymobiledevice3/restore/asr.py +27 -27
- pymobiledevice3/restore/base_restore.py +90 -47
- pymobiledevice3/restore/consts.py +87 -66
- pymobiledevice3/restore/device.py +11 -11
- pymobiledevice3/restore/fdr.py +46 -46
- pymobiledevice3/restore/ftab.py +19 -19
- pymobiledevice3/restore/img4.py +130 -133
- pymobiledevice3/restore/mbn.py +35 -54
- pymobiledevice3/restore/recovery.py +125 -135
- pymobiledevice3/restore/restore.py +524 -523
- pymobiledevice3/restore/restore_options.py +122 -115
- pymobiledevice3/restore/restored_client.py +25 -22
- pymobiledevice3/restore/tss.py +378 -270
- pymobiledevice3/service_connection.py +50 -46
- pymobiledevice3/services/accessibilityaudit.py +136 -126
- pymobiledevice3/services/afc.py +350 -291
- pymobiledevice3/services/amfi.py +21 -18
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +60 -46
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +55 -47
- pymobiledevice3/services/diagnostics.py +971 -968
- 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 +11 -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 +25 -10
- pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
- pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
- pymobiledevice3/services/dvt/testmanaged/xcuitest.py +40 -50
- pymobiledevice3/services/file_relay.py +10 -10
- pymobiledevice3/services/heartbeat.py +8 -7
- pymobiledevice3/services/house_arrest.py +12 -15
- pymobiledevice3/services/installation_proxy.py +119 -100
- pymobiledevice3/services/lockdown_service.py +12 -5
- pymobiledevice3/services/misagent.py +22 -19
- pymobiledevice3/services/mobile_activation.py +84 -72
- pymobiledevice3/services/mobile_config.py +330 -301
- pymobiledevice3/services/mobile_image_mounter.py +137 -116
- pymobiledevice3/services/mobilebackup2.py +188 -150
- pymobiledevice3/services/notification_proxy.py +11 -11
- pymobiledevice3/services/os_trace.py +69 -51
- pymobiledevice3/services/pcapd.py +306 -306
- pymobiledevice3/services/power_assertion.py +10 -9
- pymobiledevice3/services/preboard.py +4 -4
- pymobiledevice3/services/remote_fetch_symbols.py +16 -14
- pymobiledevice3/services/remote_server.py +176 -146
- pymobiledevice3/services/restore_service.py +16 -16
- pymobiledevice3/services/screenshot.py +13 -10
- 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 +3 -3
- pymobiledevice3/services/web_protocol/automation_session.py +180 -176
- pymobiledevice3/services/web_protocol/cdp_screencast.py +44 -36
- pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
- pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
- pymobiledevice3/services/web_protocol/driver.py +47 -45
- pymobiledevice3/services/web_protocol/element.py +74 -63
- pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
- pymobiledevice3/services/web_protocol/selenium_api.py +2 -2
- pymobiledevice3/services/web_protocol/session_protocol.py +15 -10
- pymobiledevice3/services/web_protocol/switch_to.py +11 -12
- pymobiledevice3/services/webinspector.py +127 -116
- pymobiledevice3/tcp_forwarder.py +35 -22
- pymobiledevice3/tunneld/api.py +20 -15
- pymobiledevice3/tunneld/server.py +212 -133
- pymobiledevice3/usbmux.py +183 -138
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/METADATA +1 -1
- pymobiledevice3-5.0.2.dist-info/RECORD +173 -0
- pymobiledevice3-5.0.0.dist-info/RECORD +0 -173
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/WHEEL +0 -0
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/top_level.txt +0 -0
|
@@ -18,88 +18,93 @@ def cli() -> None:
|
|
|
18
18
|
|
|
19
19
|
@cli.group()
|
|
20
20
|
def diagnostics() -> None:
|
|
21
|
-
"""
|
|
21
|
+
"""Reboot/Shutdown device or access other diagnostics services"""
|
|
22
22
|
pass
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
@diagnostics.command(
|
|
26
|
-
@click.option(
|
|
27
|
-
|
|
25
|
+
@diagnostics.command("restart", cls=Command)
|
|
26
|
+
@click.option(
|
|
27
|
+
"-r",
|
|
28
|
+
"--reconnect",
|
|
29
|
+
is_flag=True,
|
|
30
|
+
default=False,
|
|
31
|
+
help="Wait until the device reconnects before finishing the operation.",
|
|
32
|
+
)
|
|
28
33
|
def diagnostics_restart(service_provider: LockdownClient, reconnect):
|
|
29
|
-
"""
|
|
34
|
+
"""Restart device"""
|
|
30
35
|
DiagnosticsService(lockdown=service_provider).restart()
|
|
31
36
|
if reconnect:
|
|
32
37
|
# Wait for the device to be available again
|
|
33
38
|
with retry_create_using_usbmux(None, serial=service_provider.udid):
|
|
34
|
-
print(f
|
|
39
|
+
print(f"Device Reconnected ({service_provider.udid}).")
|
|
35
40
|
|
|
36
41
|
|
|
37
|
-
@diagnostics.command(
|
|
42
|
+
@diagnostics.command("shutdown", cls=Command)
|
|
38
43
|
def diagnostics_shutdown(service_provider: LockdownClient):
|
|
39
|
-
"""
|
|
44
|
+
"""Shutdown device"""
|
|
40
45
|
DiagnosticsService(lockdown=service_provider).shutdown()
|
|
41
46
|
|
|
42
47
|
|
|
43
|
-
@diagnostics.command(
|
|
48
|
+
@diagnostics.command("sleep", cls=Command)
|
|
44
49
|
def diagnostics_sleep(service_provider: LockdownClient):
|
|
45
|
-
"""
|
|
50
|
+
"""Put device into sleep"""
|
|
46
51
|
DiagnosticsService(lockdown=service_provider).sleep()
|
|
47
52
|
|
|
48
53
|
|
|
49
|
-
@diagnostics.command(
|
|
54
|
+
@diagnostics.command("info", cls=Command)
|
|
50
55
|
def diagnostics_info(service_provider: LockdownClient):
|
|
51
|
-
"""
|
|
56
|
+
"""Get diagnostics info"""
|
|
52
57
|
print_json(DiagnosticsService(lockdown=service_provider).info())
|
|
53
58
|
|
|
54
59
|
|
|
55
|
-
@diagnostics.command(
|
|
56
|
-
@click.option(
|
|
57
|
-
@click.option(
|
|
58
|
-
@click.option(
|
|
60
|
+
@diagnostics.command("ioregistry", cls=Command)
|
|
61
|
+
@click.option("--plane")
|
|
62
|
+
@click.option("--name")
|
|
63
|
+
@click.option("--ioclass")
|
|
59
64
|
def diagnostics_ioregistry(service_provider: LockdownClient, plane, name, ioclass):
|
|
60
|
-
"""
|
|
65
|
+
"""Get ioregistry info"""
|
|
61
66
|
print_json(DiagnosticsService(lockdown=service_provider).ioregistry(plane=plane, name=name, ioclass=ioclass))
|
|
62
67
|
|
|
63
68
|
|
|
64
|
-
@diagnostics.command(
|
|
65
|
-
@click.argument(
|
|
69
|
+
@diagnostics.command("mg", cls=Command)
|
|
70
|
+
@click.argument("keys", nargs=-1, default=None)
|
|
66
71
|
def diagnostics_mg(service_provider: LockdownClient, keys):
|
|
67
|
-
"""
|
|
72
|
+
"""Get MobileGestalt key values from given list. If empty, return all known."""
|
|
68
73
|
print_json(DiagnosticsService(lockdown=service_provider).mobilegestalt(keys=keys))
|
|
69
74
|
|
|
70
75
|
|
|
71
|
-
@diagnostics.group(
|
|
76
|
+
@diagnostics.group("battery")
|
|
72
77
|
def diagnostics_battery():
|
|
73
|
-
"""
|
|
78
|
+
"""Battery options"""
|
|
74
79
|
pass
|
|
75
80
|
|
|
76
81
|
|
|
77
|
-
@diagnostics_battery.command(
|
|
82
|
+
@diagnostics_battery.command("single", cls=Command)
|
|
78
83
|
def diagnostics_battery_single(service_provider: LockdownClient):
|
|
79
|
-
"""
|
|
84
|
+
"""get single snapshot of battery data"""
|
|
80
85
|
raw_info = DiagnosticsService(lockdown=service_provider).get_battery()
|
|
81
86
|
print_json(raw_info)
|
|
82
87
|
|
|
83
88
|
|
|
84
|
-
@diagnostics_battery.command(
|
|
89
|
+
@diagnostics_battery.command("monitor", cls=Command)
|
|
85
90
|
def diagnostics_battery_monitor(service_provider: LockdownClient):
|
|
86
|
-
"""
|
|
91
|
+
"""monitor battery usage"""
|
|
87
92
|
diagnostics = DiagnosticsService(lockdown=service_provider)
|
|
88
93
|
while True:
|
|
89
94
|
raw_info = diagnostics.get_battery()
|
|
90
95
|
info = {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
"InstantAmperage": raw_info.get("InstantAmperage"),
|
|
97
|
+
"Temperature": raw_info.get("Temperature"),
|
|
98
|
+
"Voltage": raw_info.get("Voltage"),
|
|
99
|
+
"IsCharging": raw_info.get("IsCharging"),
|
|
100
|
+
"CurrentCapacity": raw_info.get("CurrentCapacity"),
|
|
96
101
|
}
|
|
97
102
|
logger.info(info)
|
|
98
103
|
time.sleep(1)
|
|
99
104
|
|
|
100
105
|
|
|
101
|
-
@diagnostics.command(
|
|
106
|
+
@diagnostics.command("wifi", cls=Command)
|
|
102
107
|
def diagnostics_wifi(service_provider: LockdownServiceProvider) -> None:
|
|
103
|
-
"""
|
|
108
|
+
"""Query WiFi info from IORegistry"""
|
|
104
109
|
raw_info = DiagnosticsService(lockdown=service_provider).get_wifi()
|
|
105
110
|
print_json(raw_info)
|
pymobiledevice3/cli/lockdown.py
CHANGED
|
@@ -22,169 +22,174 @@ def cli() -> None:
|
|
|
22
22
|
pass
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
@cli.group(
|
|
25
|
+
@cli.group("lockdown")
|
|
26
26
|
def lockdown_group() -> None:
|
|
27
|
-
"""
|
|
27
|
+
"""Pair/Unpair device or access other lockdown services"""
|
|
28
28
|
pass
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
@lockdown_group.command(
|
|
31
|
+
@lockdown_group.command("recovery", cls=Command)
|
|
32
32
|
def lockdown_recovery(service_provider: LockdownClient):
|
|
33
|
-
"""
|
|
33
|
+
"""enter recovery"""
|
|
34
34
|
print_json(service_provider.enter_recovery())
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
@lockdown_group.command(
|
|
38
|
-
@click.argument(
|
|
37
|
+
@lockdown_group.command("service", cls=Command)
|
|
38
|
+
@click.argument("service_name")
|
|
39
39
|
def lockdown_service(service_provider: LockdownServiceProvider, service_name):
|
|
40
|
-
"""
|
|
40
|
+
"""send-receive raw service messages with a given service name"""
|
|
41
41
|
service_provider.start_lockdown_service(service_name).shell()
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
@lockdown_group.command(
|
|
45
|
-
@click.argument(
|
|
44
|
+
@lockdown_group.command("developer-service", cls=Command)
|
|
45
|
+
@click.argument("service_name")
|
|
46
46
|
def lockdown_developer_service(service_provider: LockdownServiceProvider, service_name):
|
|
47
|
-
"""
|
|
47
|
+
"""send-receive raw service messages with a given developer service name"""
|
|
48
48
|
service_provider.start_lockdown_developer_service(service_name).shell()
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
@lockdown_group.command(
|
|
51
|
+
@lockdown_group.command("info", cls=Command)
|
|
52
52
|
def lockdown_info(service_provider: LockdownServiceProvider):
|
|
53
|
-
"""
|
|
53
|
+
"""query all lockdown values"""
|
|
54
54
|
print_json(service_provider.all_values)
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
@lockdown_group.command(
|
|
58
|
-
@click.argument(
|
|
59
|
-
@click.argument(
|
|
57
|
+
@lockdown_group.command("get", cls=Command)
|
|
58
|
+
@click.argument("domain", required=False)
|
|
59
|
+
@click.argument("key", required=False)
|
|
60
60
|
def lockdown_get(service_provider: LockdownClient, domain, key):
|
|
61
|
-
"""
|
|
61
|
+
"""query lockdown values by their domain and key names"""
|
|
62
62
|
print_json(service_provider.get_value(domain=domain, key=key))
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
@lockdown_group.command(
|
|
66
|
-
@click.argument(
|
|
67
|
-
@click.argument(
|
|
68
|
-
@click.argument(
|
|
65
|
+
@lockdown_group.command("set", cls=Command)
|
|
66
|
+
@click.argument("value")
|
|
67
|
+
@click.argument("domain", required=False)
|
|
68
|
+
@click.argument("key", required=False)
|
|
69
69
|
def lockdown_set(service_provider: LockdownClient, value, domain, key):
|
|
70
|
-
"""
|
|
70
|
+
"""set a lockdown value using python's eval()"""
|
|
71
71
|
print_json(service_provider.set_value(value=eval(value), domain=domain, key=key))
|
|
72
72
|
|
|
73
73
|
|
|
74
|
-
@lockdown_group.command(
|
|
75
|
-
@click.argument(
|
|
76
|
-
@click.argument(
|
|
74
|
+
@lockdown_group.command("remove", cls=Command)
|
|
75
|
+
@click.argument("domain")
|
|
76
|
+
@click.argument("key")
|
|
77
77
|
def lockdown_remove(service_provider: LockdownClient, domain, key):
|
|
78
|
-
"""
|
|
78
|
+
"""remove a domain/key pair"""
|
|
79
79
|
print_json(service_provider.remove_value(domain=domain, key=key))
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
@lockdown_group.command(
|
|
83
|
-
@click.argument(
|
|
84
|
-
def lockdown_unpair(service_provider: LockdownClient, host_id: str = None):
|
|
85
|
-
"""
|
|
82
|
+
@lockdown_group.command("unpair", cls=CommandWithoutAutopair)
|
|
83
|
+
@click.argument("host_id", required=False)
|
|
84
|
+
def lockdown_unpair(service_provider: LockdownClient, host_id: Optional[str] = None):
|
|
85
|
+
"""unpair from connected device"""
|
|
86
86
|
service_provider.unpair(host_id=host_id)
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
@lockdown_group.command(
|
|
89
|
+
@lockdown_group.command("pair", cls=CommandWithoutAutopair)
|
|
90
90
|
def lockdown_pair(service_provider: LockdownClient):
|
|
91
|
-
"""
|
|
91
|
+
"""pair device"""
|
|
92
92
|
service_provider.pair()
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
@lockdown_group.command(
|
|
96
|
-
@click.argument(
|
|
95
|
+
@lockdown_group.command("pair-supervised", cls=CommandWithoutAutopair)
|
|
96
|
+
@click.argument("keybag", type=click.Path(file_okay=True, dir_okay=False, exists=True))
|
|
97
97
|
def lockdown_pair_supervised(service_provider: LockdownClient, keybag: str) -> None:
|
|
98
|
-
"""
|
|
98
|
+
"""pair supervised device"""
|
|
99
99
|
service_provider.pair_supervised(Path(keybag))
|
|
100
100
|
|
|
101
101
|
|
|
102
|
-
@lockdown_group.command(
|
|
103
|
-
@click.argument(
|
|
102
|
+
@lockdown_group.command("save-pair-record", cls=CommandWithoutAutopair)
|
|
103
|
+
@click.argument("output", type=click.File("wb"))
|
|
104
104
|
def lockdown_save_pair_record(service_provider: LockdownClient, output):
|
|
105
|
-
"""
|
|
105
|
+
"""save pair record to specified location"""
|
|
106
106
|
if service_provider.pair_record is None:
|
|
107
|
-
logger.error(
|
|
107
|
+
logger.error("no pairing record was found")
|
|
108
108
|
return
|
|
109
109
|
plistlib.dump(service_provider.pair_record, output)
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
@lockdown_group.command(
|
|
112
|
+
@lockdown_group.command("date", cls=Command)
|
|
113
113
|
def lockdown_date(service_provider: LockdownClient):
|
|
114
|
-
"""
|
|
114
|
+
"""get device date"""
|
|
115
115
|
print(service_provider.date)
|
|
116
116
|
|
|
117
117
|
|
|
118
|
-
@lockdown_group.command(
|
|
118
|
+
@lockdown_group.command("heartbeat", cls=Command)
|
|
119
119
|
def lockdown_heartbeat(service_provider: LockdownClient):
|
|
120
|
-
"""
|
|
120
|
+
"""start heartbeat service"""
|
|
121
121
|
HeartbeatService(service_provider).start()
|
|
122
122
|
|
|
123
123
|
|
|
124
|
-
@lockdown_group.command(
|
|
125
|
-
@click.argument(
|
|
124
|
+
@lockdown_group.command("language", cls=Command)
|
|
125
|
+
@click.argument("language", required=False)
|
|
126
126
|
def lockdown_language(service_provider: LockdownClient, language: Optional[str]) -> None:
|
|
127
|
-
"""
|
|
127
|
+
"""Get/Set current language settings"""
|
|
128
128
|
if language is not None:
|
|
129
129
|
service_provider.set_language(language)
|
|
130
130
|
print_json(service_provider.language)
|
|
131
131
|
|
|
132
132
|
|
|
133
|
-
@lockdown_group.command(
|
|
134
|
-
@click.argument(
|
|
133
|
+
@lockdown_group.command("locale", cls=Command)
|
|
134
|
+
@click.argument("locale", required=False)
|
|
135
135
|
def lockdown_locale(service_provider: LockdownClient, locale: Optional[str]) -> None:
|
|
136
|
-
"""
|
|
136
|
+
"""Get/Set current language settings"""
|
|
137
137
|
if locale is not None:
|
|
138
138
|
service_provider.set_locale(locale)
|
|
139
139
|
print_json(service_provider.locale)
|
|
140
140
|
|
|
141
141
|
|
|
142
|
-
@lockdown_group.command(
|
|
143
|
-
@click.argument(
|
|
142
|
+
@lockdown_group.command("device-name", cls=Command)
|
|
143
|
+
@click.argument("new_name", required=False)
|
|
144
144
|
def lockdown_device_name(service_provider: LockdownClient, new_name):
|
|
145
|
-
"""
|
|
145
|
+
"""get/set current device name"""
|
|
146
146
|
if new_name:
|
|
147
|
-
service_provider.set_value(new_name, key=
|
|
147
|
+
service_provider.set_value(new_name, key="DeviceName")
|
|
148
148
|
else:
|
|
149
|
-
print(f
|
|
149
|
+
print(f"{service_provider.get_value(key='DeviceName')}")
|
|
150
150
|
|
|
151
151
|
|
|
152
|
-
@lockdown_group.command(
|
|
153
|
-
@click.argument(
|
|
152
|
+
@lockdown_group.command("wifi-connections", cls=Command)
|
|
153
|
+
@click.argument("state", type=click.Choice(["on", "off"]), required=False)
|
|
154
154
|
def lockdown_wifi_connections(service_provider: LockdownClient, state):
|
|
155
|
-
"""
|
|
155
|
+
"""get/set wifi connections state"""
|
|
156
156
|
if not state:
|
|
157
157
|
# show current state
|
|
158
|
-
print_json(service_provider.get_value(domain=
|
|
158
|
+
print_json(service_provider.get_value(domain="com.apple.mobile.wireless_lockdown"))
|
|
159
159
|
else:
|
|
160
160
|
# enable/disable
|
|
161
|
-
service_provider.enable_wifi_connections = state ==
|
|
161
|
+
service_provider.enable_wifi_connections = state == "on"
|
|
162
162
|
|
|
163
163
|
|
|
164
|
-
async def async_cli_start_tunnel(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
async def async_cli_start_tunnel(service_provider: LockdownServiceProvider, script_mode: bool) -> None:
|
|
165
|
+
await tunnel_task(
|
|
166
|
+
await CoreDeviceTunnelProxy.create(service_provider),
|
|
167
|
+
script_mode=script_mode,
|
|
168
|
+
secrets=None,
|
|
169
|
+
protocol=TunnelProtocol.TCP,
|
|
170
|
+
)
|
|
168
171
|
|
|
169
172
|
|
|
170
|
-
@lockdown_group.command(
|
|
171
|
-
@click.option(
|
|
172
|
-
|
|
173
|
+
@lockdown_group.command("start-tunnel", cls=Command)
|
|
174
|
+
@click.option(
|
|
175
|
+
"--script-mode",
|
|
176
|
+
is_flag=True,
|
|
177
|
+
help="Show only HOST and port number to allow easy parsing from external shell scripts",
|
|
178
|
+
)
|
|
173
179
|
@sudo_required
|
|
174
|
-
def cli_start_tunnel(
|
|
175
|
-
|
|
176
|
-
""" start tunnel """
|
|
180
|
+
def cli_start_tunnel(service_provider: LockdownServiceProvider, script_mode: bool) -> None:
|
|
181
|
+
"""start tunnel"""
|
|
177
182
|
asyncio.run(async_cli_start_tunnel(service_provider, script_mode), debug=True)
|
|
178
183
|
|
|
179
184
|
|
|
180
|
-
@lockdown_group.command(
|
|
181
|
-
@click.argument(
|
|
185
|
+
@lockdown_group.command("assistive-touch", cls=Command)
|
|
186
|
+
@click.argument("state", type=click.Choice(["on", "off"]), required=False)
|
|
182
187
|
def lockdown_assistive_touch(service_provider: LockdownClient, state: str) -> None:
|
|
183
|
-
"""
|
|
188
|
+
"""get/set assistive touch icon state (visibility)"""
|
|
184
189
|
if not state:
|
|
185
|
-
key =
|
|
186
|
-
accessibility_values = service_provider.get_value(
|
|
190
|
+
key = "AssistiveTouchEnabledByiTunes"
|
|
191
|
+
accessibility_values = service_provider.get_value("com.apple.Accessibility")
|
|
187
192
|
print_json({key: bool(accessibility_values[key])})
|
|
188
193
|
else:
|
|
189
194
|
# enable/disable
|
|
190
|
-
service_provider.assistive_touch = state ==
|
|
195
|
+
service_provider.assistive_touch = state == "on"
|
pymobiledevice3/cli/mounter.py
CHANGED
|
@@ -7,12 +7,20 @@ from urllib.error import URLError
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
9
9
|
from pymobiledevice3.cli.cli_common import Command, print_json
|
|
10
|
-
from pymobiledevice3.exceptions import
|
|
11
|
-
|
|
10
|
+
from pymobiledevice3.exceptions import (
|
|
11
|
+
AlreadyMountedError,
|
|
12
|
+
DeveloperDiskImageNotFoundError,
|
|
13
|
+
NotMountedError,
|
|
14
|
+
UnsupportedCommandError,
|
|
15
|
+
)
|
|
12
16
|
from pymobiledevice3.lockdown import LockdownClient
|
|
13
17
|
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
14
|
-
from pymobiledevice3.services.mobile_image_mounter import
|
|
15
|
-
|
|
18
|
+
from pymobiledevice3.services.mobile_image_mounter import (
|
|
19
|
+
DeveloperDiskImageMounter,
|
|
20
|
+
MobileImageMounterService,
|
|
21
|
+
PersonalizedImageMounter,
|
|
22
|
+
auto_mount,
|
|
23
|
+
)
|
|
16
24
|
|
|
17
25
|
logger = logging.getLogger(__name__)
|
|
18
26
|
|
|
@@ -22,9 +30,9 @@ def catch_errors(func):
|
|
|
22
30
|
try:
|
|
23
31
|
return func(*args, **kwargs)
|
|
24
32
|
except AlreadyMountedError:
|
|
25
|
-
logger.
|
|
33
|
+
logger.exception("Given image was already mounted")
|
|
26
34
|
except UnsupportedCommandError:
|
|
27
|
-
logger.
|
|
35
|
+
logger.exception("Your iOS version doesn't support this command")
|
|
28
36
|
|
|
29
37
|
return update_wrapper(catch_function, func)
|
|
30
38
|
|
|
@@ -36,147 +44,156 @@ def cli() -> None:
|
|
|
36
44
|
|
|
37
45
|
@cli.group()
|
|
38
46
|
def mounter() -> None:
|
|
39
|
-
"""
|
|
47
|
+
"""Mount/Umount DeveloperDiskImage or query related info"""
|
|
40
48
|
pass
|
|
41
49
|
|
|
42
50
|
|
|
43
|
-
@mounter.command(
|
|
51
|
+
@mounter.command("list", cls=Command)
|
|
44
52
|
def mounter_list(service_provider: LockdownClient):
|
|
45
|
-
"""
|
|
53
|
+
"""list all mounted images"""
|
|
46
54
|
output = []
|
|
47
55
|
|
|
48
56
|
images = MobileImageMounterService(lockdown=service_provider).copy_devices()
|
|
49
57
|
for image in images:
|
|
50
|
-
image_signature = image.get(
|
|
58
|
+
image_signature = image.get("ImageSignature")
|
|
51
59
|
if image_signature is not None:
|
|
52
|
-
image[
|
|
60
|
+
image["ImageSignature"] = image_signature.hex()
|
|
53
61
|
output.append(image)
|
|
54
62
|
|
|
55
63
|
print_json(output)
|
|
56
64
|
|
|
57
65
|
|
|
58
|
-
@mounter.command(
|
|
59
|
-
@click.argument(
|
|
66
|
+
@mounter.command("lookup", cls=Command)
|
|
67
|
+
@click.argument("image_type")
|
|
60
68
|
def mounter_lookup(service_provider: LockdownClient, image_type):
|
|
61
|
-
"""
|
|
69
|
+
"""lookup mounter image type"""
|
|
62
70
|
try:
|
|
63
71
|
signature = MobileImageMounterService(lockdown=service_provider).lookup_image(image_type)
|
|
64
72
|
print_json(signature)
|
|
65
73
|
except NotMountedError:
|
|
66
|
-
logger.
|
|
74
|
+
logger.exception(f"Disk image of type: {image_type} is not mounted")
|
|
67
75
|
|
|
68
76
|
|
|
69
|
-
@mounter.command(
|
|
77
|
+
@mounter.command("umount-developer", cls=Command)
|
|
70
78
|
@catch_errors
|
|
71
79
|
def mounter_umount_developer(service_provider: LockdownClient):
|
|
72
|
-
"""
|
|
80
|
+
"""unmount Developer image"""
|
|
73
81
|
try:
|
|
74
82
|
DeveloperDiskImageMounter(lockdown=service_provider).umount()
|
|
75
|
-
logger.info(
|
|
83
|
+
logger.info("Developer image unmounted successfully")
|
|
76
84
|
except NotMountedError:
|
|
77
|
-
logger.
|
|
85
|
+
logger.exception("Developer image isn't currently mounted")
|
|
78
86
|
|
|
79
87
|
|
|
80
|
-
@mounter.command(
|
|
88
|
+
@mounter.command("umount-personalized", cls=Command)
|
|
81
89
|
@catch_errors
|
|
82
90
|
def mounter_umount_personalized(service_provider: LockdownClient):
|
|
83
|
-
"""
|
|
91
|
+
"""unmount Personalized image"""
|
|
84
92
|
try:
|
|
85
93
|
PersonalizedImageMounter(lockdown=service_provider).umount()
|
|
86
|
-
logger.info(
|
|
94
|
+
logger.info("Personalized image unmounted successfully")
|
|
87
95
|
except NotMountedError:
|
|
88
|
-
logger.
|
|
96
|
+
logger.exception("Personalized image isn't currently mounted")
|
|
89
97
|
|
|
90
98
|
|
|
91
|
-
@mounter.command(
|
|
92
|
-
@click.argument(
|
|
93
|
-
@click.argument(
|
|
99
|
+
@mounter.command("mount-developer", cls=Command)
|
|
100
|
+
@click.argument("image", type=click.Path(exists=True, file_okay=True, dir_okay=False))
|
|
101
|
+
@click.argument("signature", type=click.Path(exists=True, file_okay=True, dir_okay=False))
|
|
94
102
|
@catch_errors
|
|
95
103
|
def mounter_mount_developer(service_provider: LockdownServiceProvider, image: str, signature: str) -> None:
|
|
96
|
-
"""
|
|
104
|
+
"""mount developer image"""
|
|
97
105
|
DeveloperDiskImageMounter(lockdown=service_provider).mount(Path(image), Path(signature))
|
|
98
|
-
logger.info(
|
|
106
|
+
logger.info("Developer image mounted successfully")
|
|
99
107
|
|
|
100
108
|
|
|
101
|
-
async def mounter_mount_personalized_task(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
async def mounter_mount_personalized_task(
|
|
110
|
+
service_provider: LockdownServiceProvider, image: str, trust_cache: str, build_manifest: str
|
|
111
|
+
) -> None:
|
|
112
|
+
await PersonalizedImageMounter(lockdown=service_provider).mount(
|
|
113
|
+
Path(image), Path(build_manifest), Path(trust_cache)
|
|
114
|
+
)
|
|
115
|
+
logger.info("Personalized image mounted successfully")
|
|
106
116
|
|
|
107
117
|
|
|
108
|
-
@mounter.command(
|
|
109
|
-
@click.argument(
|
|
110
|
-
@click.argument(
|
|
111
|
-
@click.argument(
|
|
118
|
+
@mounter.command("mount-personalized", cls=Command)
|
|
119
|
+
@click.argument("image", type=click.Path(exists=True, file_okay=True, dir_okay=False))
|
|
120
|
+
@click.argument("trust-cache", type=click.Path(exists=True, file_okay=True, dir_okay=False))
|
|
121
|
+
@click.argument("build-manifest", type=click.Path(exists=True, file_okay=True, dir_okay=False))
|
|
112
122
|
@catch_errors
|
|
113
|
-
def mounter_mount_personalized(
|
|
114
|
-
|
|
115
|
-
|
|
123
|
+
def mounter_mount_personalized(
|
|
124
|
+
service_provider: LockdownServiceProvider, image: str, trust_cache: str, build_manifest: str
|
|
125
|
+
) -> None:
|
|
126
|
+
"""mount personalized image"""
|
|
116
127
|
asyncio.run(mounter_mount_personalized_task(service_provider, image, trust_cache, build_manifest), debug=True)
|
|
117
128
|
|
|
118
129
|
|
|
119
130
|
async def mounter_auto_mount_task(service_provider: LockdownServiceProvider, xcode: str, version: str) -> None:
|
|
120
131
|
try:
|
|
121
132
|
await auto_mount(service_provider, xcode=xcode, version=version)
|
|
122
|
-
logger.info(
|
|
133
|
+
logger.info("DeveloperDiskImage mounted successfully")
|
|
123
134
|
except URLError:
|
|
124
|
-
logger.warning(
|
|
135
|
+
logger.warning("failed to query DeveloperDiskImage versions")
|
|
125
136
|
except DeveloperDiskImageNotFoundError:
|
|
126
|
-
logger.
|
|
137
|
+
logger.exception("Unable to find the correct DeveloperDiskImage")
|
|
127
138
|
except AlreadyMountedError:
|
|
128
|
-
logger.
|
|
139
|
+
logger.exception("DeveloperDiskImage already mounted")
|
|
129
140
|
except PermissionError as e:
|
|
130
|
-
logger.
|
|
131
|
-
f
|
|
132
|
-
f
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
@
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
141
|
+
logger.exception(
|
|
142
|
+
f"DeveloperDiskImage could not be saved to Xcode default path ({e.filename}). "
|
|
143
|
+
f"Please make sure your user has the necessary permissions"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@mounter.command("auto-mount", cls=Command)
|
|
148
|
+
@click.option(
|
|
149
|
+
"-x",
|
|
150
|
+
"--xcode",
|
|
151
|
+
type=click.Path(exists=True, dir_okay=True, file_okay=False),
|
|
152
|
+
help="Xcode application path used to figure out automatically the DeveloperDiskImage path",
|
|
153
|
+
)
|
|
154
|
+
@click.option(
|
|
155
|
+
"--version", help="use a different DeveloperDiskImage version from the one retrieved by lockdownconnection"
|
|
156
|
+
)
|
|
140
157
|
def mounter_auto_mount(service_provider: LockdownServiceProvider, xcode: str, version: str) -> None:
|
|
141
|
-
"""
|
|
158
|
+
"""auto-detect correct DeveloperDiskImage and mount it"""
|
|
142
159
|
asyncio.run(mounter_auto_mount_task(service_provider, xcode, version), debug=True)
|
|
143
160
|
|
|
144
161
|
|
|
145
|
-
@mounter.command(
|
|
162
|
+
@mounter.command("query-developer-mode-status", cls=Command)
|
|
146
163
|
def mounter_query_developer_mode_status(service_provider: LockdownClient):
|
|
147
|
-
"""
|
|
164
|
+
"""Query developer mode status"""
|
|
148
165
|
print_json(MobileImageMounterService(lockdown=service_provider).query_developer_mode_status())
|
|
149
166
|
|
|
150
167
|
|
|
151
|
-
@mounter.command(
|
|
152
|
-
@click.option(
|
|
168
|
+
@mounter.command("query-nonce", cls=Command)
|
|
169
|
+
@click.option("--image-type")
|
|
153
170
|
def mounter_query_nonce(service_provider: LockdownClient, image_type: str):
|
|
154
|
-
"""
|
|
171
|
+
"""Query nonce"""
|
|
155
172
|
print_json(MobileImageMounterService(lockdown=service_provider).query_nonce(image_type))
|
|
156
173
|
|
|
157
174
|
|
|
158
|
-
@mounter.command(
|
|
175
|
+
@mounter.command("query-personalization-identifiers", cls=Command)
|
|
159
176
|
def mounter_query_personalization_identifiers(service_provider: LockdownClient):
|
|
160
|
-
"""
|
|
177
|
+
"""Query personalization identifiers"""
|
|
161
178
|
print_json(MobileImageMounterService(lockdown=service_provider).query_personalization_identifiers())
|
|
162
179
|
|
|
163
180
|
|
|
164
|
-
@mounter.command(
|
|
181
|
+
@mounter.command("query-personalization-manifest", cls=Command)
|
|
165
182
|
def mounter_query_personalization_manifest(service_provider: LockdownClient):
|
|
166
|
-
"""
|
|
183
|
+
"""Query personalization manifest"""
|
|
167
184
|
result = []
|
|
168
185
|
mounter = MobileImageMounterService(lockdown=service_provider)
|
|
169
186
|
for device in mounter.copy_devices():
|
|
170
|
-
result.append(mounter.query_personalization_manifest(device[
|
|
187
|
+
result.append(mounter.query_personalization_manifest(device["PersonalizedImageType"], device["ImageSignature"]))
|
|
171
188
|
print_json(result)
|
|
172
189
|
|
|
173
190
|
|
|
174
|
-
@mounter.command(
|
|
191
|
+
@mounter.command("roll-personalization-nonce", cls=Command)
|
|
175
192
|
def mounter_roll_personalization_nonce(service_provider: LockdownClient):
|
|
176
193
|
MobileImageMounterService(lockdown=service_provider).roll_personalization_nonce()
|
|
177
194
|
|
|
178
195
|
|
|
179
|
-
@mounter.command(
|
|
196
|
+
@mounter.command("roll-cryptex-nonce", cls=Command)
|
|
180
197
|
def mounter_roll_cryptex_nonce(service_provider: LockdownClient):
|
|
181
|
-
"""
|
|
198
|
+
"""Roll cryptex nonce (will reboot)"""
|
|
182
199
|
MobileImageMounterService(lockdown=service_provider).roll_cryptex_nonce()
|