pymobiledevice3 4.27.4__py3-none-any.whl → 5.1.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.
- misc/plist_sniffer.py +15 -15
- misc/remotexpc_sniffer.py +29 -28
- pymobiledevice3/__main__.py +123 -98
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/bonjour.py +351 -117
- 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 +27 -20
- 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 +601 -519
- pymobiledevice3/cli/diagnostics.py +38 -33
- pymobiledevice3/cli/lockdown.py +82 -72
- pymobiledevice3/cli/mounter.py +84 -67
- 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 +188 -111
- 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 +156 -78
- pymobiledevice3/common.py +1 -1
- pymobiledevice3/exceptions.py +154 -60
- pymobiledevice3/irecv.py +49 -53
- pymobiledevice3/irecv_devices.py +1489 -492
- pymobiledevice3/lockdown.py +400 -251
- 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 +64 -42
- pymobiledevice3/remote/tunnel_service.py +383 -297
- 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 +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 +587 -0
- pymobiledevice3/restore/recovery.py +125 -135
- pymobiledevice3/restore/restore.py +535 -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 +137 -127
- pymobiledevice3/services/afc.py +352 -292
- pymobiledevice3/services/amfi.py +21 -18
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +61 -47
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +56 -48
- 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 +42 -52
- 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 +331 -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 +128 -74
- 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 +183 -179
- 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 +3 -3
- pymobiledevice3/services/web_protocol/session_protocol.py +15 -10
- pymobiledevice3/services/web_protocol/switch_to.py +11 -12
- pymobiledevice3/services/webinspector.py +142 -116
- pymobiledevice3/tcp_forwarder.py +35 -22
- pymobiledevice3/tunneld/api.py +20 -15
- pymobiledevice3/tunneld/server.py +310 -193
- pymobiledevice3/usbmux.py +197 -148
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/METADATA +1 -2
- pymobiledevice3-5.1.2.dist-info/RECORD +173 -0
- pymobiledevice3-4.27.4.dist-info/RECORD +0 -172
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/WHEEL +0 -0
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/top_level.txt +0 -0
pymobiledevice3/cli/afc.py
CHANGED
|
@@ -13,44 +13,44 @@ def cli() -> None:
|
|
|
13
13
|
|
|
14
14
|
@cli.group()
|
|
15
15
|
def afc() -> None:
|
|
16
|
-
"""
|
|
16
|
+
"""Manage device multimedia files"""
|
|
17
17
|
pass
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
@afc.command(
|
|
20
|
+
@afc.command("shell", cls=Command)
|
|
21
21
|
def afc_shell(service_provider: LockdownClient):
|
|
22
|
-
"""
|
|
22
|
+
"""open an AFC shell rooted at /var/mobile/Media"""
|
|
23
23
|
AfcShell.create(service_provider)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
@afc.command(
|
|
27
|
-
@click.option(
|
|
28
|
-
@click.argument(
|
|
29
|
-
@click.argument(
|
|
26
|
+
@afc.command("pull", cls=Command)
|
|
27
|
+
@click.option("-i", "--ignore-errors", is_flag=True, help="Ignore AFC pull errors")
|
|
28
|
+
@click.argument("remote_file", type=click.Path(exists=False))
|
|
29
|
+
@click.argument("local_file", type=click.Path(exists=False))
|
|
30
30
|
def afc_pull(service_provider: LockdownServiceProvider, remote_file: str, local_file: str, ignore_errors: bool) -> None:
|
|
31
|
-
"""
|
|
31
|
+
"""pull remote file from /var/mobile/Media"""
|
|
32
32
|
AfcService(lockdown=service_provider).pull(remote_file, local_file, ignore_errors=ignore_errors)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
@afc.command(
|
|
36
|
-
@click.argument(
|
|
37
|
-
@click.argument(
|
|
35
|
+
@afc.command("push", cls=Command)
|
|
36
|
+
@click.argument("local_file", type=click.Path(exists=False))
|
|
37
|
+
@click.argument("remote_file", type=click.Path(exists=False))
|
|
38
38
|
def afc_push(service_provider: LockdownServiceProvider, local_file: str, remote_file: str) -> None:
|
|
39
|
-
"""
|
|
39
|
+
"""push local file into /var/mobile/Media"""
|
|
40
40
|
AfcService(lockdown=service_provider).push(local_file, remote_file)
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
@afc.command(
|
|
44
|
-
@click.argument(
|
|
45
|
-
@click.option(
|
|
43
|
+
@afc.command("ls", cls=Command)
|
|
44
|
+
@click.argument("remote_file", type=click.Path(exists=False))
|
|
45
|
+
@click.option("-r", "--recursive", is_flag=True)
|
|
46
46
|
def afc_ls(service_provider: LockdownClient, remote_file, recursive):
|
|
47
|
-
"""
|
|
47
|
+
"""perform a dirlist rooted at /var/mobile/Media"""
|
|
48
48
|
for path in AfcService(lockdown=service_provider).dirlist(remote_file, -1 if recursive else 1):
|
|
49
49
|
print(path)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
@afc.command(
|
|
53
|
-
@click.argument(
|
|
52
|
+
@afc.command("rm", cls=Command)
|
|
53
|
+
@click.argument("remote_file", type=click.Path(exists=False))
|
|
54
54
|
def afc_rm(service_provider: LockdownClient, remote_file):
|
|
55
|
-
"""
|
|
55
|
+
"""remove a file rooted at /var/mobile/Media"""
|
|
56
56
|
AfcService(lockdown=service_provider).rm(remote_file)
|
pymobiledevice3/cli/amfi.py
CHANGED
|
@@ -16,23 +16,23 @@ def cli() -> None:
|
|
|
16
16
|
|
|
17
17
|
@cli.group()
|
|
18
18
|
def amfi() -> None:
|
|
19
|
-
"""
|
|
19
|
+
"""Enable developer-mode or query its state"""
|
|
20
20
|
pass
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
@amfi.command(cls=Command)
|
|
24
24
|
def reveal_developer_mode(service_provider: LockdownClient):
|
|
25
|
-
"""
|
|
25
|
+
"""reveal developer mode option in device's UI"""
|
|
26
26
|
AmfiService(service_provider).reveal_developer_mode_option_in_ui()
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@amfi.command(cls=Command)
|
|
30
30
|
def enable_developer_mode(service_provider: LockdownClient):
|
|
31
|
-
"""
|
|
31
|
+
"""enable developer mode"""
|
|
32
32
|
AmfiService(service_provider).enable_developer_mode()
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
@amfi.command(cls=Command)
|
|
36
36
|
def developer_mode_status(service_provider: LockdownClient):
|
|
37
|
-
"""
|
|
37
|
+
"""query developer mode status"""
|
|
38
38
|
print_json(service_provider.developer_mode_status)
|
pymobiledevice3/cli/apps.py
CHANGED
|
@@ -14,73 +14,85 @@ def cli() -> None:
|
|
|
14
14
|
|
|
15
15
|
@cli.group()
|
|
16
16
|
def apps() -> None:
|
|
17
|
-
"""
|
|
17
|
+
"""Manage installed applications"""
|
|
18
18
|
pass
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
@apps.command(
|
|
22
|
-
@click.option(
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
@apps.command("list", cls=Command)
|
|
22
|
+
@click.option(
|
|
23
|
+
"app_type",
|
|
24
|
+
"-t",
|
|
25
|
+
"--type",
|
|
26
|
+
type=click.Choice(["System", "User", "Hidden", "Any"]),
|
|
27
|
+
default="Any",
|
|
28
|
+
help="include only applications of given type",
|
|
29
|
+
)
|
|
30
|
+
@click.option("--calculate-sizes/--no-calculate-size", default=False)
|
|
25
31
|
def apps_list(service_provider: LockdownServiceProvider, app_type: str, calculate_sizes: bool) -> None:
|
|
26
|
-
"""
|
|
27
|
-
print_json(
|
|
28
|
-
|
|
32
|
+
"""list installed apps"""
|
|
33
|
+
print_json(
|
|
34
|
+
InstallationProxyService(lockdown=service_provider).get_apps(
|
|
35
|
+
application_type=app_type, calculate_sizes=calculate_sizes
|
|
36
|
+
)
|
|
37
|
+
)
|
|
29
38
|
|
|
30
39
|
|
|
31
|
-
@apps.command(
|
|
32
|
-
@click.argument(
|
|
33
|
-
@click.option(
|
|
40
|
+
@apps.command("query", cls=Command)
|
|
41
|
+
@click.argument("bundle_identifiers", nargs=-1)
|
|
42
|
+
@click.option("--calculate-sizes/--no-calculate-size", default=False)
|
|
34
43
|
def apps_query(service_provider: LockdownServiceProvider, bundle_identifiers: list[str], calculate_sizes: bool) -> None:
|
|
35
|
-
"""
|
|
36
|
-
print_json(
|
|
37
|
-
|
|
44
|
+
"""query installed apps"""
|
|
45
|
+
print_json(
|
|
46
|
+
InstallationProxyService(lockdown=service_provider).get_apps(
|
|
47
|
+
calculate_sizes=calculate_sizes, bundle_identifiers=bundle_identifiers
|
|
48
|
+
)
|
|
49
|
+
)
|
|
38
50
|
|
|
39
51
|
|
|
40
|
-
@apps.command(
|
|
41
|
-
@click.argument(
|
|
52
|
+
@apps.command("uninstall", cls=Command)
|
|
53
|
+
@click.argument("bundle_id")
|
|
42
54
|
def uninstall(service_provider: LockdownClient, bundle_id):
|
|
43
|
-
"""
|
|
55
|
+
"""uninstall app by given bundle_id"""
|
|
44
56
|
InstallationProxyService(lockdown=service_provider).uninstall(bundle_id)
|
|
45
57
|
|
|
46
58
|
|
|
47
|
-
@apps.command(
|
|
48
|
-
@click.option(
|
|
49
|
-
@click.argument(
|
|
59
|
+
@apps.command("install", cls=Command)
|
|
60
|
+
@click.option("--developer", is_flag=True, help="Install developer package")
|
|
61
|
+
@click.argument("package", type=click.Path(exists=True))
|
|
50
62
|
def install(service_provider: LockdownServiceProvider, package: str, developer: bool) -> None:
|
|
51
|
-
"""
|
|
63
|
+
"""install given .ipa/.app/.ipcc"""
|
|
52
64
|
InstallationProxyService(lockdown=service_provider).install_from_local(package, developer=developer)
|
|
53
65
|
|
|
54
66
|
|
|
55
|
-
@apps.command(
|
|
56
|
-
@click.option(
|
|
57
|
-
@click.argument(
|
|
67
|
+
@apps.command("afc", cls=Command)
|
|
68
|
+
@click.option("--documents", is_flag=True)
|
|
69
|
+
@click.argument("bundle_id")
|
|
58
70
|
def afc(service_provider: LockdownClient, bundle_id: str, documents: bool):
|
|
59
|
-
"""
|
|
71
|
+
"""open an AFC shell for given bundle_id, assuming its profile is installed"""
|
|
60
72
|
HouseArrestService(lockdown=service_provider, bundle_id=bundle_id, documents_only=documents).shell()
|
|
61
73
|
|
|
62
74
|
|
|
63
|
-
@apps.command(
|
|
64
|
-
@click.argument(
|
|
65
|
-
@click.argument(
|
|
66
|
-
@click.argument(
|
|
75
|
+
@apps.command("pull", cls=Command)
|
|
76
|
+
@click.argument("bundle_id")
|
|
77
|
+
@click.argument("remote_file", type=click.Path(exists=False))
|
|
78
|
+
@click.argument("local_file", type=click.Path(exists=False))
|
|
67
79
|
def pull(service_provider: LockdownClient, bundle_id: str, remote_file: str, local_file: str):
|
|
68
|
-
"""
|
|
80
|
+
"""pull remote file from specified bundle_id"""
|
|
69
81
|
HouseArrestService(lockdown=service_provider, bundle_id=bundle_id).pull(remote_file, local_file)
|
|
70
82
|
|
|
71
83
|
|
|
72
|
-
@apps.command(
|
|
73
|
-
@click.argument(
|
|
74
|
-
@click.argument(
|
|
75
|
-
@click.argument(
|
|
84
|
+
@apps.command("push", cls=Command)
|
|
85
|
+
@click.argument("bundle_id")
|
|
86
|
+
@click.argument("local_file", type=click.Path(exists=False))
|
|
87
|
+
@click.argument("remote_file", type=click.Path(exists=False))
|
|
76
88
|
def push(service_provider: LockdownClient, bundle_id: str, local_file: str, remote_file: str):
|
|
77
|
-
"""
|
|
89
|
+
"""push local file into specified bundle_id"""
|
|
78
90
|
HouseArrestService(lockdown=service_provider, bundle_id=bundle_id).push(local_file, remote_file)
|
|
79
91
|
|
|
80
92
|
|
|
81
|
-
@apps.command(
|
|
82
|
-
@click.argument(
|
|
83
|
-
@click.argument(
|
|
93
|
+
@apps.command("rm", cls=Command)
|
|
94
|
+
@click.argument("bundle_id")
|
|
95
|
+
@click.argument("remote_file", type=click.Path(exists=False))
|
|
84
96
|
def rm(service_provider: LockdownClient, bundle_id: str, remote_file: str):
|
|
85
|
-
"""
|
|
97
|
+
"""remove remote file from specified bundle_id"""
|
|
86
98
|
HouseArrestService(lockdown=service_provider, bundle_id=bundle_id).rm(remote_file)
|
pymobiledevice3/cli/backup.py
CHANGED
|
@@ -8,11 +8,12 @@ from pymobiledevice3.lockdown import LockdownClient
|
|
|
8
8
|
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
9
9
|
from pymobiledevice3.services.mobilebackup2 import Mobilebackup2Service
|
|
10
10
|
|
|
11
|
-
source_option = click.option(
|
|
12
|
-
password_option = click.option(
|
|
13
|
-
backup_directory_arg = click.argument(
|
|
14
|
-
backup_directory_option = click.option(
|
|
15
|
-
|
|
11
|
+
source_option = click.option("--source", default="", help="The UDID of the source device.")
|
|
12
|
+
password_option = click.option("-p", "--password", default="", help="Backup password.")
|
|
13
|
+
backup_directory_arg = click.argument("backup-directory", type=click.Path(exists=True, file_okay=False))
|
|
14
|
+
backup_directory_option = click.option(
|
|
15
|
+
"-b", "--backup-directory", type=click.Path(exists=True, file_okay=False), default="."
|
|
16
|
+
)
|
|
16
17
|
|
|
17
18
|
logger = logging.getLogger(__name__)
|
|
18
19
|
|
|
@@ -24,14 +25,17 @@ def cli() -> None:
|
|
|
24
25
|
|
|
25
26
|
@cli.group()
|
|
26
27
|
def backup2() -> None:
|
|
27
|
-
"""
|
|
28
|
+
"""Backup/Restore options"""
|
|
28
29
|
pass
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
@backup2.command(cls=Command)
|
|
32
|
-
@click.argument(
|
|
33
|
-
@click.option(
|
|
34
|
-
|
|
33
|
+
@click.argument("backup-directory", type=click.Path(file_okay=False))
|
|
34
|
+
@click.option(
|
|
35
|
+
"--full",
|
|
36
|
+
is_flag=True,
|
|
37
|
+
help=("Whether to do a full backup. If full is True, any previous backup attempts will be discarded."),
|
|
38
|
+
)
|
|
35
39
|
def backup(service_provider: LockdownServiceProvider, backup_directory: str, full: bool) -> None:
|
|
36
40
|
"""
|
|
37
41
|
Backup device.
|
|
@@ -40,6 +44,7 @@ def backup(service_provider: LockdownServiceProvider, backup_directory: str, ful
|
|
|
40
44
|
"""
|
|
41
45
|
backup_client = Mobilebackup2Service(service_provider)
|
|
42
46
|
with tqdm(total=100, dynamic_ncols=True) as pbar:
|
|
47
|
+
|
|
43
48
|
def update_bar(percentage):
|
|
44
49
|
pbar.n = percentage
|
|
45
50
|
pbar.refresh()
|
|
@@ -49,16 +54,26 @@ def backup(service_provider: LockdownServiceProvider, backup_directory: str, ful
|
|
|
49
54
|
|
|
50
55
|
@backup2.command(cls=Command)
|
|
51
56
|
@backup_directory_arg
|
|
52
|
-
@click.option(
|
|
53
|
-
@click.option(
|
|
54
|
-
@click.option(
|
|
55
|
-
@click.option(
|
|
56
|
-
@click.option(
|
|
57
|
-
@click.option(
|
|
57
|
+
@click.option("--system/--no-system", default=False, help="Restore system files.")
|
|
58
|
+
@click.option("--reboot/--no-reboot", default=True, help="Reboot the device when done.")
|
|
59
|
+
@click.option("--copy/--no-copy", default=False, help="Create a copy of backup folder before restoring.")
|
|
60
|
+
@click.option("--settings/--no-settings", default=True, help="Restore device settings.")
|
|
61
|
+
@click.option("--remove/--no-remove", default=False, help="Remove items which aren't being restored.")
|
|
62
|
+
@click.option("--skip-apps", is_flag=True, help="Do not trigger re-installation of apps after restore")
|
|
58
63
|
@password_option
|
|
59
64
|
@source_option
|
|
60
|
-
def restore(
|
|
61
|
-
|
|
65
|
+
def restore(
|
|
66
|
+
service_provider: LockdownServiceProvider,
|
|
67
|
+
backup_directory: str,
|
|
68
|
+
system: bool,
|
|
69
|
+
reboot: bool,
|
|
70
|
+
copy: bool,
|
|
71
|
+
settings: bool,
|
|
72
|
+
remove: bool,
|
|
73
|
+
skip_apps: bool,
|
|
74
|
+
password: str,
|
|
75
|
+
source: str,
|
|
76
|
+
) -> None:
|
|
62
77
|
"""
|
|
63
78
|
Restore a backup to a device.
|
|
64
79
|
|
|
@@ -66,13 +81,23 @@ def restore(service_provider: LockdownServiceProvider, backup_directory: str, sy
|
|
|
66
81
|
"""
|
|
67
82
|
backup_client = Mobilebackup2Service(service_provider)
|
|
68
83
|
with tqdm(total=100, dynamic_ncols=True) as pbar:
|
|
84
|
+
|
|
69
85
|
def update_bar(percentage):
|
|
70
86
|
pbar.n = percentage
|
|
71
87
|
pbar.refresh()
|
|
72
88
|
|
|
73
|
-
backup_client.restore(
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
backup_client.restore(
|
|
90
|
+
backup_directory=backup_directory,
|
|
91
|
+
progress_callback=update_bar,
|
|
92
|
+
system=system,
|
|
93
|
+
reboot=reboot,
|
|
94
|
+
copy=copy,
|
|
95
|
+
settings=settings,
|
|
96
|
+
remove=remove,
|
|
97
|
+
password=password,
|
|
98
|
+
source=source,
|
|
99
|
+
skip_apps=skip_apps,
|
|
100
|
+
)
|
|
76
101
|
|
|
77
102
|
|
|
78
103
|
@backup2.command(cls=Command)
|
|
@@ -86,7 +111,7 @@ def info(service_provider: LockdownClient, backup_directory, source):
|
|
|
86
111
|
print(backup_client.info(backup_directory=backup_directory, source=source))
|
|
87
112
|
|
|
88
113
|
|
|
89
|
-
@backup2.command(
|
|
114
|
+
@backup2.command("list", cls=Command)
|
|
90
115
|
@backup_directory_arg
|
|
91
116
|
@source_option
|
|
92
117
|
def list_(service_provider: LockdownClient, backup_directory, source):
|
|
@@ -110,8 +135,8 @@ def unback(service_provider: LockdownClient, backup_directory, password, source)
|
|
|
110
135
|
|
|
111
136
|
|
|
112
137
|
@backup2.command(cls=Command)
|
|
113
|
-
@click.argument(
|
|
114
|
-
@click.argument(
|
|
138
|
+
@click.argument("domain-name")
|
|
139
|
+
@click.argument("relative-path")
|
|
115
140
|
@backup_directory_arg
|
|
116
141
|
@password_option
|
|
117
142
|
@source_option
|
|
@@ -123,13 +148,14 @@ def extract(service_provider: LockdownClient, domain_name, relative_path, backup
|
|
|
123
148
|
will be extracted to the BACKUP_DIRECTORY.
|
|
124
149
|
"""
|
|
125
150
|
backup_client = Mobilebackup2Service(service_provider)
|
|
126
|
-
backup_client.extract(
|
|
127
|
-
|
|
151
|
+
backup_client.extract(
|
|
152
|
+
domain_name, relative_path, backup_directory=backup_directory, password=password, source=source
|
|
153
|
+
)
|
|
128
154
|
|
|
129
155
|
|
|
130
156
|
@backup2.command(cls=Command)
|
|
131
|
-
@click.argument(
|
|
132
|
-
@click.argument(
|
|
157
|
+
@click.argument("mode", type=click.Choice(["on", "off"], case_sensitive=False))
|
|
158
|
+
@click.argument("password")
|
|
133
159
|
@backup_directory_option
|
|
134
160
|
def encryption(service_provider: LockdownClient, backup_directory, mode, password):
|
|
135
161
|
"""
|
|
@@ -139,9 +165,9 @@ def encryption(service_provider: LockdownClient, backup_directory, mode, passwor
|
|
|
139
165
|
When off, PASSWORD is the current backup password.
|
|
140
166
|
"""
|
|
141
167
|
backup_client = Mobilebackup2Service(service_provider)
|
|
142
|
-
should_encrypt = mode.lower() ==
|
|
168
|
+
should_encrypt = mode.lower() == "on"
|
|
143
169
|
if should_encrypt == backup_client.will_encrypt:
|
|
144
|
-
logger.error(
|
|
170
|
+
logger.error("Encryption already " + ("on!" if should_encrypt else "off!"))
|
|
145
171
|
return
|
|
146
172
|
if should_encrypt:
|
|
147
173
|
backup_client.change_password(backup_directory, new=password)
|
|
@@ -150,8 +176,8 @@ def encryption(service_provider: LockdownClient, backup_directory, mode, passwor
|
|
|
150
176
|
|
|
151
177
|
|
|
152
178
|
@backup2.command(cls=Command)
|
|
153
|
-
@click.argument(
|
|
154
|
-
@click.argument(
|
|
179
|
+
@click.argument("old-password")
|
|
180
|
+
@click.argument("new-password")
|
|
155
181
|
@backup_directory_option
|
|
156
182
|
def change_password(service_provider: LockdownClient, old_password, new_password, backup_directory):
|
|
157
183
|
"""
|
|
@@ -159,7 +185,7 @@ def change_password(service_provider: LockdownClient, old_password, new_password
|
|
|
159
185
|
"""
|
|
160
186
|
backup_client = Mobilebackup2Service(service_provider)
|
|
161
187
|
if not backup_client.will_encrypt:
|
|
162
|
-
logger.error(
|
|
188
|
+
logger.error("Encryption is not turned on!")
|
|
163
189
|
return
|
|
164
190
|
backup_client.change_password(backup_directory, old=old_password, new=new_password)
|
|
165
191
|
|
pymobiledevice3/cli/bonjour.py
CHANGED
|
@@ -14,9 +14,9 @@ def cli() -> None:
|
|
|
14
14
|
pass
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
@cli.group(
|
|
17
|
+
@cli.group("bonjour")
|
|
18
18
|
def bonjour_cli() -> None:
|
|
19
|
-
"""
|
|
19
|
+
"""Browse devices over bonjour"""
|
|
20
20
|
pass
|
|
21
21
|
|
|
22
22
|
|
|
@@ -24,47 +24,54 @@ async def cli_mobdev2_task(timeout: float, pair_records: Optional[str]) -> None:
|
|
|
24
24
|
output = []
|
|
25
25
|
async for ip, lockdown in get_mobdev2_lockdowns(timeout=timeout, pair_records=pair_records):
|
|
26
26
|
short_info = lockdown.short_info
|
|
27
|
-
short_info[
|
|
27
|
+
short_info["ip"] = ip
|
|
28
28
|
output.append(short_info)
|
|
29
29
|
print_json(output)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
@bonjour_cli.command(
|
|
33
|
-
@click.option(
|
|
34
|
-
@click.option(
|
|
35
|
-
|
|
32
|
+
@bonjour_cli.command("mobdev2", cls=BaseCommand)
|
|
33
|
+
@click.option("--timeout", default=DEFAULT_BONJOUR_TIMEOUT, type=click.INT)
|
|
34
|
+
@click.option(
|
|
35
|
+
"--pair-records",
|
|
36
|
+
type=click.Path(dir_okay=True, file_okay=False, exists=True),
|
|
37
|
+
help="pair records to attempt validation with",
|
|
38
|
+
)
|
|
36
39
|
def cli_mobdev2(timeout: float, pair_records: Optional[str]) -> None:
|
|
37
|
-
"""
|
|
40
|
+
"""browse for mobdev2 devices over bonjour"""
|
|
38
41
|
asyncio.run(cli_mobdev2_task(timeout, pair_records))
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
async def cli_remotepairing_task(timeout: float) -> None:
|
|
42
45
|
output = []
|
|
43
46
|
for answer in await browse_remotepairing(timeout=timeout):
|
|
44
|
-
for
|
|
45
|
-
output.append({
|
|
47
|
+
for address in answer.addresses:
|
|
48
|
+
output.append({"hostname": address.full_ip, "port": answer.port})
|
|
46
49
|
print_json(output)
|
|
47
50
|
|
|
48
51
|
|
|
49
|
-
@bonjour_cli.command(
|
|
50
|
-
@click.option(
|
|
52
|
+
@bonjour_cli.command("remotepairing", cls=BaseCommand)
|
|
53
|
+
@click.option("--timeout", default=DEFAULT_BONJOUR_TIMEOUT, type=click.FLOAT)
|
|
51
54
|
def cli_remotepairing(timeout: float) -> None:
|
|
52
|
-
"""
|
|
55
|
+
"""browse for remotepairing devices over bonjour (without attempting pair verification)"""
|
|
53
56
|
asyncio.run(cli_remotepairing_task(timeout=timeout))
|
|
54
57
|
|
|
55
58
|
|
|
56
59
|
async def cli_remotepairing_manual_pairing_task(timeout: float) -> None:
|
|
57
60
|
output = []
|
|
58
61
|
for answer in await browse_remotepairing_manual_pairing(timeout=timeout):
|
|
59
|
-
for
|
|
60
|
-
output.append({
|
|
62
|
+
for address in answer.addresses:
|
|
63
|
+
output.append({
|
|
64
|
+
"hostname": address.full_ip,
|
|
65
|
+
"port": answer.port,
|
|
66
|
+
"name": answer.properties[b"name"].decode(),
|
|
67
|
+
})
|
|
61
68
|
print_json(output)
|
|
62
69
|
|
|
63
70
|
|
|
64
|
-
@bonjour_cli.command(
|
|
65
|
-
@click.option(
|
|
71
|
+
@bonjour_cli.command("remotepairing-manual-pairing", cls=BaseCommand)
|
|
72
|
+
@click.option("--timeout", default=DEFAULT_BONJOUR_TIMEOUT, type=click.FLOAT)
|
|
66
73
|
def cli_remotepairing_manual_pairing(timeout: float) -> None:
|
|
67
|
-
"""
|
|
74
|
+
"""browse for remotepairing-manual-pairing devices over bonjour"""
|
|
68
75
|
asyncio.run(cli_remotepairing_manual_pairing_task(timeout=timeout))
|
|
69
76
|
|
|
70
77
|
|
|
@@ -72,7 +79,7 @@ async def cli_browse_rsd() -> None:
|
|
|
72
79
|
print_json(await browse_rsd())
|
|
73
80
|
|
|
74
81
|
|
|
75
|
-
@bonjour_cli.command(
|
|
82
|
+
@bonjour_cli.command("rsd", cls=BaseCommand)
|
|
76
83
|
def cli_rsd() -> None:
|
|
77
|
-
"""
|
|
84
|
+
"""browse RemoteXPC devices using bonjour"""
|
|
78
85
|
asyncio.run(cli_browse_rsd(), debug=True)
|