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