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
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
import dataclasses
|
|
3
|
+
import logging
|
|
3
4
|
import plistlib
|
|
4
5
|
import xml.etree.ElementTree as ET
|
|
5
6
|
from contextlib import closing
|
|
6
7
|
from pathlib import Path
|
|
8
|
+
from typing import Optional
|
|
7
9
|
|
|
8
10
|
import click
|
|
9
11
|
import inquirer3
|
|
10
12
|
import requests
|
|
13
|
+
from requests.structures import CaseInsensitiveDict
|
|
11
14
|
|
|
12
15
|
from pymobiledevice3.exceptions import MobileActivationException
|
|
13
|
-
from pymobiledevice3.lockdown import create_using_usbmux
|
|
14
16
|
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
15
17
|
|
|
16
|
-
ACTIVATION_USER_AGENT_IOS =
|
|
17
|
-
ACTIVATION_DEFAULT_URL =
|
|
18
|
-
ACTIVATION_DRM_HANDSHAKE_DEFAULT_URL =
|
|
18
|
+
ACTIVATION_USER_AGENT_IOS = "iOS Device Activator (MobileActivation-20 built on Jan 15 2012 at 19:07:28)"
|
|
19
|
+
ACTIVATION_DEFAULT_URL = "https://albert.apple.com/deviceservices/deviceActivation"
|
|
20
|
+
ACTIVATION_DRM_HANDSHAKE_DEFAULT_URL = "https://albert.apple.com/deviceservices/drmHandshake"
|
|
19
21
|
DEFAULT_HEADERS = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
"Accept": "application/xml",
|
|
23
|
+
"User-Agent": ACTIVATION_USER_AGENT_IOS,
|
|
24
|
+
"Expect": "100-continue",
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
ACTIVATION_REQUESTS_SUBDIR = Path(
|
|
27
|
+
ACTIVATION_REQUESTS_SUBDIR = Path("offline_requests")
|
|
26
28
|
NONCE_CYCLE_INTERVAL = 60 * 5
|
|
27
29
|
|
|
28
30
|
|
|
@@ -49,104 +51,185 @@ class MobileActivationService:
|
|
|
49
51
|
There is no point in inheriting from BaseService since we'll need a new lockdown connection
|
|
50
52
|
for each request.
|
|
51
53
|
"""
|
|
52
|
-
|
|
54
|
+
|
|
55
|
+
SERVICE_NAME = "com.apple.mobileactivationd"
|
|
53
56
|
|
|
54
57
|
def __init__(self, lockdown: LockdownServiceProvider) -> None:
|
|
55
58
|
self.lockdown = lockdown
|
|
59
|
+
self.logger = logging.getLogger(__name__)
|
|
56
60
|
|
|
57
61
|
@property
|
|
58
62
|
def state(self):
|
|
59
|
-
|
|
63
|
+
try:
|
|
64
|
+
return self.send_command("GetActivationStateRequest")["Value"]
|
|
65
|
+
except Exception:
|
|
66
|
+
return self.lockdown.get_value(key="ActivationState")
|
|
60
67
|
|
|
61
68
|
def wait_for_activation_session(self):
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
try:
|
|
70
|
+
blob = self.create_activation_session_info()
|
|
71
|
+
except Exception:
|
|
72
|
+
return
|
|
73
|
+
handshake_request_message = blob["HandshakeRequestMessage"]
|
|
74
|
+
while handshake_request_message == blob["HandshakeRequestMessage"]:
|
|
65
75
|
blob = self.create_activation_session_info()
|
|
66
76
|
|
|
67
77
|
@staticmethod
|
|
68
78
|
def _get_activation_form_from_response(content: str) -> ActivationForm:
|
|
69
79
|
root = ET.fromstring(content)
|
|
70
|
-
title = root.find(
|
|
71
|
-
description = root.find(
|
|
80
|
+
title = root.find("page/navigationBar").get("title")
|
|
81
|
+
description = root.find("page/tableView/section/footer").text
|
|
72
82
|
fields = []
|
|
73
|
-
for editable in root.findall(
|
|
83
|
+
for editable in root.findall("page//editableTextRow"):
|
|
74
84
|
fields.append(
|
|
75
|
-
Field(
|
|
76
|
-
|
|
85
|
+
Field(
|
|
86
|
+
id=editable.get("id"),
|
|
87
|
+
label=editable.get("label"),
|
|
88
|
+
placeholder=editable.get("placeholder"),
|
|
89
|
+
secure=bool(editable.get("secure", False)),
|
|
90
|
+
)
|
|
91
|
+
)
|
|
77
92
|
server_info = {}
|
|
78
|
-
for k, v in root.find(
|
|
93
|
+
for k, v in root.find("serverInfo").items():
|
|
79
94
|
server_info[k] = v
|
|
80
95
|
return ActivationForm(title=title, description=description, fields=fields, server_info=server_info)
|
|
81
96
|
|
|
82
97
|
def activate(self, skip_apple_id_query: bool = False) -> None:
|
|
83
|
-
|
|
98
|
+
if self.state != "Unactivated":
|
|
99
|
+
self.logger.error("Device is already activated!")
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
blob = self.create_activation_session_info()
|
|
104
|
+
session_mode = True
|
|
105
|
+
except Exception:
|
|
106
|
+
session_mode = False
|
|
84
107
|
|
|
85
108
|
# create drmHandshake request with blob from device
|
|
86
|
-
headers = {
|
|
109
|
+
headers = {"Content-Type": "application/x-apple-plist"}
|
|
87
110
|
headers.update(DEFAULT_HEADERS)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
111
|
+
if session_mode:
|
|
112
|
+
content, headers = self.post(
|
|
113
|
+
ACTIVATION_DRM_HANDSHAKE_DEFAULT_URL, data=plistlib.dumps(blob), headers=headers
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
activation_request = {}
|
|
117
|
+
if session_mode:
|
|
118
|
+
activation_info = self.create_activation_info_with_session(content)
|
|
119
|
+
else:
|
|
120
|
+
activation_info = self.lockdown.get_value(key="ActivationInfo")
|
|
121
|
+
activation_request.update({
|
|
122
|
+
"InStoreActivation": False,
|
|
123
|
+
"AppleSerialNumber": self.lockdown.get_value(key="SerialNumber"),
|
|
124
|
+
})
|
|
125
|
+
if self.lockdown.all_values.get("TelephonyCapability"):
|
|
126
|
+
req_pair = {
|
|
127
|
+
"IMEI": "InternationalMobileEquipmentIdentity",
|
|
128
|
+
"MEID": "MobileEquipmentIdentifier",
|
|
129
|
+
"IMSI": "InternationalMobileSubscriberIdentity",
|
|
130
|
+
"ICCID": "IntegratedCircuitCardIdentity",
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
has_meid = False
|
|
134
|
+
for k, v in req_pair.items():
|
|
135
|
+
lv = self.lockdown.all_values.get(v)
|
|
136
|
+
if lv is not None:
|
|
137
|
+
activation_request.update({k: lv})
|
|
138
|
+
continue
|
|
139
|
+
else:
|
|
140
|
+
self.logger.warn(f"Unable to get {k} from lockdownd")
|
|
141
|
+
if k == "MEID" and has_meid:
|
|
142
|
+
# Something is wrong if both IMEI & MEID is missing
|
|
143
|
+
raise MobileActivationException("Unable to obtain both IMEI and MEID")
|
|
144
|
+
|
|
145
|
+
# Either IMEI or MEID, or both
|
|
146
|
+
if k == "IMEI":
|
|
147
|
+
has_meid = lv is None
|
|
148
|
+
activation_request.update({"activation-info": plistlib.dumps(activation_info)})
|
|
149
|
+
|
|
150
|
+
content, headers = self.post(ACTIVATION_DEFAULT_URL, data=activation_request)
|
|
151
|
+
content_type = headers["Content-Type"]
|
|
152
|
+
|
|
153
|
+
if content_type == "application/x-buddyml":
|
|
96
154
|
if skip_apple_id_query:
|
|
97
|
-
raise MobileActivationException(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
155
|
+
raise MobileActivationException("Device is iCloud locked")
|
|
156
|
+
try:
|
|
157
|
+
activation_form = self._get_activation_form_from_response(content.decode())
|
|
158
|
+
except Exception as e:
|
|
159
|
+
raise MobileActivationException("Activation server response is invalid") from e
|
|
160
|
+
else:
|
|
161
|
+
click.secho(activation_form.title, bold=True)
|
|
162
|
+
click.secho(activation_form.description)
|
|
163
|
+
fields = []
|
|
164
|
+
for field in activation_form.fields:
|
|
165
|
+
if field.secure:
|
|
166
|
+
fields.append(inquirer3.Password(name=field.id, message=f"{field.label}"))
|
|
167
|
+
else:
|
|
168
|
+
fields.append(inquirer3.Text(name=field.id, message=f"{field.label}"))
|
|
169
|
+
data = inquirer3.prompt(fields)
|
|
170
|
+
data.update(activation_form.server_info)
|
|
171
|
+
content, headers = self.post(ACTIVATION_DEFAULT_URL, data=data)
|
|
172
|
+
content_type = headers["Content-Type"]
|
|
173
|
+
|
|
174
|
+
assert content_type == "text/xml"
|
|
175
|
+
if session_mode:
|
|
176
|
+
self.activate_with_session(content, headers)
|
|
177
|
+
else:
|
|
178
|
+
self.activate_with_lockdown(content)
|
|
179
|
+
|
|
180
|
+
# set ActivationStateAcknowledged if we succeeded
|
|
181
|
+
self.lockdown.set_value(True, key="ActivationStateAcknowledged")
|
|
114
182
|
|
|
115
183
|
def deactivate(self):
|
|
116
|
-
|
|
184
|
+
try:
|
|
185
|
+
return self.send_command("DeactivateRequest")
|
|
186
|
+
except Exception:
|
|
187
|
+
return self.lockdown._request("Deactivate")
|
|
117
188
|
|
|
118
189
|
def create_activation_session_info(self):
|
|
119
|
-
response = self.send_command(
|
|
120
|
-
error = response.get(
|
|
190
|
+
response = self.send_command("CreateTunnel1SessionInfoRequest")
|
|
191
|
+
error = response.get("Error")
|
|
121
192
|
if error is not None:
|
|
122
|
-
raise MobileActivationException(f
|
|
123
|
-
return response[
|
|
193
|
+
raise MobileActivationException(f"Mobile activation can not be done due to: {response}")
|
|
194
|
+
return response["Value"]
|
|
124
195
|
|
|
125
196
|
def create_activation_info_with_session(self, handshake_response):
|
|
126
|
-
response = self.send_command(
|
|
127
|
-
error = response.get(
|
|
197
|
+
response = self.send_command("CreateTunnel1ActivationInfoRequest", handshake_response)
|
|
198
|
+
error = response.get("Error")
|
|
128
199
|
if error is not None:
|
|
129
|
-
raise MobileActivationException(f
|
|
130
|
-
return response[
|
|
200
|
+
raise MobileActivationException(f"Mobile activation can not be done due to: {response}")
|
|
201
|
+
return response["Value"]
|
|
202
|
+
|
|
203
|
+
def activate_with_lockdown(self, activation_record):
|
|
204
|
+
record = plistlib.loads(activation_record)
|
|
205
|
+
node = record.get("iphone-activation")
|
|
206
|
+
if node is None:
|
|
207
|
+
node = record.get("device-activation")
|
|
208
|
+
if node is None:
|
|
209
|
+
raise MobileActivationException("Activation record received is invalid")
|
|
210
|
+
|
|
211
|
+
self.lockdown._request("Activate", {"ActivationRecord": node.get("activation-record")})
|
|
131
212
|
|
|
132
213
|
def activate_with_session(self, activation_record, headers):
|
|
133
214
|
data = {
|
|
134
|
-
|
|
135
|
-
|
|
215
|
+
"Command": "HandleActivationInfoWithSessionRequest",
|
|
216
|
+
"Value": activation_record,
|
|
136
217
|
}
|
|
137
218
|
if headers:
|
|
138
|
-
data[
|
|
139
|
-
with closing(
|
|
219
|
+
data["ActivationResponseHeaders"] = dict(headers)
|
|
220
|
+
with closing(self.lockdown.start_lockdown_service(self.SERVICE_NAME)) as service:
|
|
140
221
|
return service.send_recv_plist(data)
|
|
141
222
|
|
|
142
|
-
def send_command(self, command, value=
|
|
143
|
-
data = {
|
|
223
|
+
def send_command(self, command: str, value: str = ""):
|
|
224
|
+
data = {"Command": command}
|
|
144
225
|
if value:
|
|
145
|
-
data[
|
|
146
|
-
with closing(
|
|
226
|
+
data["Value"] = value
|
|
227
|
+
with closing(self.lockdown.start_lockdown_service(self.SERVICE_NAME)) as service:
|
|
147
228
|
return service.send_recv_plist(data)
|
|
148
229
|
|
|
149
|
-
def post(
|
|
230
|
+
def post(
|
|
231
|
+
self, url: str, data: dict, headers: Optional[CaseInsensitiveDict[str, str]] = None
|
|
232
|
+
) -> tuple[bytes, CaseInsensitiveDict[str]]:
|
|
150
233
|
if headers is None:
|
|
151
234
|
headers = DEFAULT_HEADERS
|
|
152
235
|
|