2023-10-22 16:27:11 -05:00
|
|
|
import base64
|
2023-10-21 19:39:40 -05:00
|
|
|
import logging
|
2023-10-22 16:27:11 -05:00
|
|
|
import plistlib
|
|
|
|
import uuid
|
|
|
|
|
2023-10-21 19:39:40 -05:00
|
|
|
import requests
|
|
|
|
|
|
|
|
from emulated import nac
|
|
|
|
|
2023-10-22 16:27:11 -05:00
|
|
|
from . import gsa
|
|
|
|
|
2023-10-21 19:39:40 -05:00
|
|
|
logger = logging.getLogger("icloud")
|
|
|
|
|
|
|
|
USER_AGENT = "com.apple.iCloudHelper/282 CFNetwork/1408.0.4 Darwin/22.5.0"
|
|
|
|
|
2023-10-22 16:27:11 -05:00
|
|
|
|
|
|
|
def login(
|
|
|
|
username: str,
|
|
|
|
password: str,
|
|
|
|
delegates: set[str] = ["com.apple.private.ids"],
|
|
|
|
grandslam: bool = True,
|
|
|
|
anisette: str | bool = False,
|
|
|
|
):
|
2023-10-21 19:39:40 -05:00
|
|
|
"""
|
|
|
|
Logs into Apple services listed in `delegates` and returns a dictionary of responses.
|
|
|
|
Commonly used delegates are:
|
|
|
|
- `com.apple.private.ids`
|
|
|
|
- `com.apple.mobileme`
|
|
|
|
|
|
|
|
`grandslam` configures if the new GrandSlam authentication flow is used. This is required for some delegates, and improves the 2FA experience.
|
|
|
|
`anisette` configures which server to request anisette data from. If `False`, local anisette generation using AOSKit is attempted. This is not required if `grandslam` is `False`.
|
|
|
|
"""
|
|
|
|
|
|
|
|
if grandslam:
|
|
|
|
# TODO: Provide anisette preferences to gsa.authenticate
|
|
|
|
g = gsa.authenticate(username, password)
|
|
|
|
# Replace the password with the PET token
|
|
|
|
password = g["t"]["com.apple.gs.idms.pet"]["token"]
|
|
|
|
adsid = g["adsid"]
|
|
|
|
logger.debug("Authenticated with GrandSlam")
|
|
|
|
|
|
|
|
delegates = {delegate: {} for delegate in delegates}
|
|
|
|
if "com.apple.private.ids" in delegates:
|
|
|
|
delegates["com.apple.private.ids"]["protocol-version"] = "4"
|
|
|
|
|
|
|
|
data = {
|
|
|
|
"apple-id": username,
|
|
|
|
"delegates": delegates,
|
|
|
|
"password": password,
|
|
|
|
"client-id": str(uuid.uuid4()),
|
|
|
|
}
|
|
|
|
data = plistlib.dumps(data)
|
|
|
|
|
|
|
|
logger.debug("Generating validation data")
|
|
|
|
v = nac.generate_validation_data()
|
|
|
|
logger.debug("Generated validation data")
|
|
|
|
|
|
|
|
headers = {
|
|
|
|
"X-Apple-ADSID": adsid,
|
|
|
|
"X-Mme-Nas-Qualify": base64.b64encode(v).decode(),
|
|
|
|
"User-Agent": USER_AGENT,
|
2023-10-22 16:27:11 -05:00
|
|
|
"X-Mme-Client-Info": gsa.build_client(
|
|
|
|
emulated_app="accountsd"
|
|
|
|
), # Otherwise we get MOBILEME_TERMS_OF_SERVICE_UPDATE on some accounts
|
2023-10-21 19:39:40 -05:00
|
|
|
}
|
|
|
|
headers.update(gsa.generate_anisette_headers())
|
|
|
|
|
|
|
|
logger.debug("Making login request")
|
|
|
|
r = requests.post(
|
|
|
|
"https://setup.icloud.com/setup/prefpane/login",
|
|
|
|
auth=(username, password),
|
|
|
|
data=data,
|
|
|
|
headers=headers,
|
|
|
|
verify=False,
|
|
|
|
)
|
2023-10-22 16:27:11 -05:00
|
|
|
|
2023-10-21 19:39:40 -05:00
|
|
|
# TODO: Error checking and parsing of this response
|
2023-10-22 16:27:11 -05:00
|
|
|
return plistlib.loads(r.content)
|