mirror of
https://github.com/Sneed-Group/pypush-plus-plus
synced 2024-12-24 03:42:43 -06:00
refactor gsa.py
This commit is contained in:
parent
0775466b98
commit
8e75cd2969
2 changed files with 137 additions and 272 deletions
|
@ -26,13 +26,8 @@ else:
|
|||
USERNAME = input("Username: ")
|
||||
PASSWORD = input("Password: ")
|
||||
|
||||
anisette = gsa.Anisette()
|
||||
|
||||
print("Anisette headers:", anisette.generate_headers())
|
||||
|
||||
|
||||
print("Authenticating with Grand Slam...")
|
||||
g = gsa.authenticate(USERNAME, PASSWORD, anisette)
|
||||
g = gsa.authenticate(USERNAME, PASSWORD)
|
||||
#print(g)
|
||||
pet = g["t"]["com.apple.gs.idms.pet"]["token"]
|
||||
print("Authenticated!")
|
||||
|
@ -55,14 +50,13 @@ else:
|
|||
|
||||
headers = {
|
||||
"X-Apple-ADSID": g["adsid"],
|
||||
"X-Mme-Nas-Qualify": b64encode(v),
|
||||
"User-Agent": "com.apple.iCloudHelper/282 CFNetwork/1408.0.4 Darwin/22.5.0"
|
||||
"X-Mme-Nas-Qualify": b64encode(v).decode(),
|
||||
"User-Agent": "com.apple.iCloudHelper/282 CFNetwork/1408.0.4 Darwin/22.5.0",
|
||||
"X-Mme-Client-Info": gsa.build_client(emulated_app="accountsd") # Otherwise we get MOBILEME_TERMS_OF_SERVICE_UPDATE on some accounts
|
||||
}
|
||||
headers.update(anisette.generate_headers())
|
||||
# Otherwise we get MOBILEME_TERMS_OF_SERVICE_UPDATE on some accounts
|
||||
# Really should just change it in gsa.py
|
||||
headers["X-Mme-Client-Info"]= "<MacBookPro18,3> <Mac OS X;13.4.1;22F82> <com.apple.AOSKit/282 (com.apple.accountsd/113)>"
|
||||
#print(headers)
|
||||
headers.update(gsa.generate_anisette_headers())
|
||||
|
||||
print(headers)
|
||||
|
||||
print("Logging in to iCloud...")
|
||||
r = requests.post(
|
||||
|
@ -71,18 +65,18 @@ else:
|
|||
data=data,
|
||||
headers=headers,
|
||||
verify=False,
|
||||
|
||||
)
|
||||
|
||||
print(r)
|
||||
print(r.headers)
|
||||
r = plistlib.loads(r.content)
|
||||
print(r)
|
||||
|
||||
search_party_token = r['delegates']['com.apple.mobileme']['service-data']['tokens']['searchPartyToken']
|
||||
ds_prs_id = r['delegates']['com.apple.mobileme']['service-data']['appleAccountInfo']['dsPrsID'] # This can also be obtained from the grandslam response
|
||||
#print(r)
|
||||
|
||||
print("Logged in!")
|
||||
|
||||
# print("Search Party Token: ", search_party_token)
|
||||
|
||||
with open(CONFIG_PATH, "w") as f:
|
||||
json.dump({
|
||||
"search_party_token": search_party_token,
|
||||
|
@ -91,13 +85,10 @@ else:
|
|||
|
||||
import time
|
||||
|
||||
#print("Search Party Token: ", search_party_token)
|
||||
|
||||
|
||||
r = requests.post(
|
||||
"https://gateway.icloud.com/acsnservice/fetch",
|
||||
auth=(ds_prs_id, search_party_token),
|
||||
headers=gsa.Anisette().generate_headers(),
|
||||
headers=gsa.generate_anisette_headers(),
|
||||
json={
|
||||
"search": [
|
||||
{
|
||||
|
|
342
gsa.py
342
gsa.py
|
@ -17,15 +17,19 @@ import srp._pysrp as srp
|
|||
from cryptography.hazmat.primitives import padding
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
|
||||
# Constants
|
||||
DEBUG = True # Allows using a proxy for debugging (disables SSL verification)
|
||||
|
||||
# Server to use for anisette generation
|
||||
ANISETTE = False # Use local generation with AOSKit (macOS only)
|
||||
# ANISETTE = "https://sign.rheaa.xyz/"
|
||||
# ANISETTE = 'http://45.132.246.138:6969/'
|
||||
ANISETTE = "https://ani.sidestore.io/"
|
||||
#ANISETTE = "https://ani.sidestore.io/"
|
||||
# ANISETTE = 'https://sideloadly.io/anisette/irGb3Quww8zrhgqnzmrx'
|
||||
# ANISETTE = "http://jkcoxson.com:2052/"
|
||||
|
||||
# Created here so that it is consistent
|
||||
USER_ID = uuid.uuid4()
|
||||
DEVICE_ID = uuid.uuid4()
|
||||
|
||||
# Configure SRP library for compatibility with Apple's implementation
|
||||
srp.rfc5054_enable()
|
||||
srp.no_username_in_x()
|
||||
|
@ -35,190 +39,7 @@ import urllib3
|
|||
|
||||
urllib3.disable_warnings()
|
||||
|
||||
|
||||
def generate_anisette() -> dict:
|
||||
import objc
|
||||
from Foundation import NSBundle, NSClassFromString # type: ignore
|
||||
|
||||
AOSKitBundle = NSBundle.bundleWithPath_(
|
||||
"/System/Library/PrivateFrameworks/AOSKit.framework"
|
||||
)
|
||||
objc.loadBundleFunctions(AOSKitBundle, globals(), [("retrieveOTPHeadersForDSID", b"")]) # type: ignore
|
||||
util = NSClassFromString("AOSUtilities")
|
||||
|
||||
h = util.retrieveOTPHeadersForDSID_("-2")
|
||||
|
||||
o = {
|
||||
"X-Apple-I-MD": str(h["X-Apple-MD"]),
|
||||
"X-Apple-I-MD-M": str(h["X-Apple-MD-M"]),
|
||||
}
|
||||
# h["X-Apple-I-MD"] = str(h["X-Apple-MD"])
|
||||
# h["X-Apple-I-MD-M"] = str(h["X-Apple-MD-M"])
|
||||
# print(o)
|
||||
return o
|
||||
# r = requests.get(ANISETTE, verify=False if DEBUG else True, timeout=5)
|
||||
# r = json.loads(r.text)
|
||||
# return r
|
||||
|
||||
|
||||
class Anisette:
|
||||
@staticmethod
|
||||
def _fetch(url: str) -> dict:
|
||||
"""Fetches anisette data that we cannot calculate from a remote server"""
|
||||
if url == False:
|
||||
return generate_anisette()
|
||||
r = requests.get(url, verify=False if DEBUG else True, timeout=5)
|
||||
r = json.loads(r.text)
|
||||
return r
|
||||
|
||||
def __init__(self, url: str = ANISETTE, name: str = "") -> None:
|
||||
self._name = name
|
||||
self._url = url
|
||||
self._anisette = self._fetch(self._url)
|
||||
|
||||
# Generate a "user id": just a random UUID
|
||||
# TODO: Figure out how to tie it to the user's account on the device
|
||||
self._user_id = str(uuid.uuid4()).upper()
|
||||
self._device_id = str(uuid.uuid4()).upper()
|
||||
|
||||
# override string printing
|
||||
def __str__(self) -> str:
|
||||
return f"{self._name} ({self.backend})"
|
||||
|
||||
@property
|
||||
def url(self) -> str:
|
||||
return self._url
|
||||
|
||||
@property
|
||||
def backend(self) -> str:
|
||||
if (
|
||||
self._anisette["X-MMe-Client-Info"]
|
||||
== "<MacBookPro15,1> <Mac OS X;10.15.2;19C57> <com.apple.AuthKit/1 (com.apple.dt.Xcode/3594.4.19)>"
|
||||
):
|
||||
return "AltServer"
|
||||
elif (
|
||||
self._anisette["X-MMe-Client-Info"]
|
||||
== "<iMac11,3> <Mac OS X;10.15.6;19G2021> <com.apple.AuthKit/1 (com.apple.dt.Xcode/3594.4.19)>"
|
||||
):
|
||||
return "Provision"
|
||||
else:
|
||||
return f"Unknown ({self._anisette['X-MMe-Client-Info']})"
|
||||
|
||||
# Getters
|
||||
@property
|
||||
def timestamp(self) -> str:
|
||||
"""'Timestamp'
|
||||
Current timestamp in ISO 8601 format
|
||||
"""
|
||||
|
||||
# We only want sencond precision, so we set the microseconds to 0
|
||||
# We also add 'Z' to the end to indicate UTC
|
||||
# An alternate way to write this is strftime("%FT%T%zZ")
|
||||
return datetime.utcnow().replace(microsecond=0).isoformat() + "Z"
|
||||
|
||||
@property
|
||||
def timezone(self) -> str:
|
||||
"""'Time Zone'
|
||||
Abbreviation of the timezone of the device (e.g. EST)"""
|
||||
|
||||
return str(datetime.utcnow().astimezone().tzinfo)
|
||||
|
||||
@property
|
||||
def locale(self) -> str:
|
||||
"""'Locale'
|
||||
Locale of the device (e.g. en_US)
|
||||
"""
|
||||
|
||||
return locale.getdefaultlocale()[0] or "en_US"
|
||||
|
||||
@property
|
||||
def otp(self) -> str:
|
||||
"""'One Time Password'
|
||||
A seemingly random base64 string containing 28 bytes
|
||||
TODO: Figure out how to generate this
|
||||
"""
|
||||
|
||||
return self._anisette["X-Apple-I-MD"]
|
||||
|
||||
@property
|
||||
def local_user(self) -> str:
|
||||
"""'Local User ID'
|
||||
There are 2 possible implementations of this value
|
||||
1. Uppercase hex of the SHA256 hash of some unknown value (used by Windows based servers)
|
||||
2. Base64 encoding of an uppercase UUID (used by android based servers)
|
||||
I picked the second one because it's more fully understood.
|
||||
"""
|
||||
|
||||
return b64encode(self._user_id.encode()).decode()
|
||||
|
||||
@property
|
||||
def machine(self) -> str:
|
||||
"""'Machine ID'
|
||||
This is a base64 encoded string of 60 'random' bytes
|
||||
We're not sure how this is generated, we have to rely on the server
|
||||
TODO: Figure out how to generate this
|
||||
"""
|
||||
|
||||
return self._anisette["X-Apple-I-MD-M"]
|
||||
|
||||
@property
|
||||
def router(self) -> str:
|
||||
"""'Routing Info'
|
||||
This is a number, either 17106176 or 50660608
|
||||
It doesn't seem to matter which one we use,
|
||||
17106176 is used by Sideloadly and Provision (android) based servers
|
||||
50660608 is used by Windows iCloud based servers
|
||||
"""
|
||||
|
||||
return "17106176"
|
||||
|
||||
@property
|
||||
def serial(self) -> str:
|
||||
"""'Device Serial Number'
|
||||
This is the serial number of the device
|
||||
You can use a legitimate serial number, but Apple accepts '0' as well (for andriod devices)
|
||||
See https://github.com/acidanthera/OpenCorePkg/blob/master/Utilities/macserial/macserial.c for how to generate a legit serial
|
||||
"""
|
||||
|
||||
return "0"
|
||||
|
||||
@property
|
||||
def device(self) -> str:
|
||||
"""'Device Unique Identifier'
|
||||
This is just an uppercase UUID"""
|
||||
|
||||
return self._device_id
|
||||
|
||||
def _build_client(self, emulated_device: str, emulated_app: str) -> str:
|
||||
# TODO: Update OS version and app versions
|
||||
|
||||
model = emulated_device
|
||||
if emulated_device == "PC":
|
||||
# We're emulating a PC, so we run Windows (Vista?)
|
||||
os = "Windows"
|
||||
os_version = "6.2(0,0);9200"
|
||||
else:
|
||||
# We're emulating a Mac, so we run macOS (What is 15.6?)
|
||||
os = "Mac OS X"
|
||||
os_version = "10.15.6;19G2021"
|
||||
|
||||
if emulated_app == "Xcode":
|
||||
app_bundle = "com.apple.dt.Xcode"
|
||||
app_version = "3594.4.19"
|
||||
else:
|
||||
app_bundle = "com.apple.iCloud"
|
||||
app_version = "7.21"
|
||||
|
||||
if os == "Windows":
|
||||
authkit_bundle = "com.apple.AuthKitWin"
|
||||
else:
|
||||
authkit_bundle = "com.apple.AuthKit"
|
||||
authkit_version = "1"
|
||||
|
||||
return f"<{model}> <{os};{os_version}> <{authkit_bundle}/{authkit_version} ({app_bundle}/{app_version})>"
|
||||
|
||||
@property
|
||||
def client(self) -> str:
|
||||
def build_client(emulated_device: str = "MacBookPro18,3", emulated_app: str = "accountsd") -> str:
|
||||
"""'Client Information'
|
||||
String in the following format:
|
||||
<%MODEL%> <%OS%;%MAJOR%.%MINOR%(%SPMAJOR%,%SPMINOR%);%BUILD%> <%AUTHKIT_BUNDLE_ID%/%AUTHKIT_VERSION% (%APP_BUNDLE_ID%/%APP_VERSION%)>
|
||||
|
@ -235,40 +56,37 @@ class Anisette:
|
|||
APP_BUNDLE_ID: The bundle ID of the app (e.g. com.apple.dt.Xcode)
|
||||
APP_VERSION: The version of the app (e.g. 3594.4.19)
|
||||
"""
|
||||
return self._build_client("iMac11,3", "Xcode")
|
||||
|
||||
def generate_headers(self, client_info: bool = False) -> dict:
|
||||
h = {
|
||||
# Current Time
|
||||
"X-Apple-I-Client-Time": self.timestamp,
|
||||
"X-Apple-I-TimeZone": self.timezone,
|
||||
# Locale
|
||||
# Some implementations only use this for locale
|
||||
"loc": self.locale,
|
||||
"X-Apple-Locale": self.locale,
|
||||
# Anisette
|
||||
"X-Apple-I-MD": self.otp, # 'One Time Password'
|
||||
# 'Local User ID'
|
||||
"X-Apple-I-MD-LU": self.local_user,
|
||||
"X-Apple-I-MD-M": self.machine, # 'Machine ID'
|
||||
# 'Routing Info', some implementations convert this to an integer
|
||||
"X-Apple-I-MD-RINFO": self.router,
|
||||
# Device information
|
||||
# 'Device Unique Identifier'
|
||||
"X-Mme-Device-Id": self.device,
|
||||
# 'Device Serial Number'
|
||||
"X-Apple-I-SRL-NO": self.serial,
|
||||
}
|
||||
model = emulated_device
|
||||
if emulated_device == "PC":
|
||||
# We're emulating a PC, so we run Windows (Vista?)
|
||||
os = "Windows"
|
||||
os_version = "6.2(0,0);9200"
|
||||
else:
|
||||
# We're emulating a Mac, so we run macOS Ventura
|
||||
os = "Mac OS X"
|
||||
os_version = "13.4.1;22F8"
|
||||
|
||||
# Additional client information only used in some requests
|
||||
if client_info:
|
||||
h["X-Mme-Client-Info"] = self.client
|
||||
h["X-Apple-App-Info"] = "com.apple.gs.xcode.auth"
|
||||
h["X-Xcode-Version"] = "11.2 (11B41)"
|
||||
if emulated_app == "Xcode":
|
||||
app_bundle = "com.apple.dt.Xcode"
|
||||
app_version = "3594.4.19"
|
||||
elif emulated_app == "accountsd":
|
||||
app_bundle = "com.apple.accountsd"
|
||||
app_version = "113"
|
||||
else:
|
||||
app_bundle = "com.apple.iCloud"
|
||||
app_version = "7.21"
|
||||
|
||||
return h
|
||||
if os == "Windows":
|
||||
authkit_bundle = "com.apple.AuthKitWin"
|
||||
authkit_version = "1"
|
||||
else:
|
||||
authkit_bundle = "com.apple.AOSKit"
|
||||
authkit_version = "282"
|
||||
|
||||
def generate_cpd(self) -> dict:
|
||||
return f"<{model}> <{os};{os_version}> <{authkit_bundle}/{authkit_version} ({app_bundle}/{app_version})>"
|
||||
|
||||
def _generate_cpd() -> dict:
|
||||
cpd = {
|
||||
# Many of these values are not strictly necessary, but may be tracked by Apple
|
||||
# I've chosen to match the AltServer implementation
|
||||
|
@ -285,17 +103,70 @@ class Anisette:
|
|||
# 'prtn': 'ME349',
|
||||
}
|
||||
|
||||
cpd.update(self.generate_headers())
|
||||
cpd.update(generate_anisette_headers())
|
||||
return cpd
|
||||
|
||||
def _generate_meta_headers(serial: str = "0", user_id: uuid = uuid.uuid4(), device_id: uuid = uuid.uuid4()) -> dict:
|
||||
return {
|
||||
"X-Apple-I-Client-Time": datetime.utcnow().replace(microsecond=0).isoformat() + "Z", # Current timestamp in ISO 8601 format
|
||||
"X-Apple-I-TimeZone": str(datetime.utcnow().astimezone().tzinfo), # Abbreviation of the timezone of the device (e.g. EST)
|
||||
|
||||
def authenticated_request(parameters, anisette: Anisette) -> dict:
|
||||
# Locale of the device (e.g. en_US)
|
||||
"loc": locale.getdefaultlocale()[0] or "en_US",
|
||||
"X-Apple-Locale": locale.getdefaultlocale()[0] or "en_US",
|
||||
|
||||
"X-Apple-I-MD-RINFO": "17106176", # either 17106176 or 50660608
|
||||
|
||||
"X-Apple-I-MD-LU": b64encode(str(user_id).upper().encode()).decode(), # 'Local User ID': Base64 encoding of an uppercase UUID
|
||||
"X-Mme-Device-Id": str(device_id).upper(), # 'Device Unique Identifier', uppercase UUID
|
||||
"X-Apple-I-SRL-NO": serial, # Serial number
|
||||
}
|
||||
|
||||
def _generate_local_anisette() -> dict:
|
||||
print("Using local anisette generation")
|
||||
"""Generates anisette data using AOSKit locally"""
|
||||
|
||||
import objc
|
||||
from Foundation import NSBundle, NSClassFromString # type: ignore
|
||||
|
||||
AOSKitBundle = NSBundle.bundleWithPath_(
|
||||
"/System/Library/PrivateFrameworks/AOSKit.framework"
|
||||
)
|
||||
objc.loadBundleFunctions(AOSKitBundle, globals(), [("retrieveOTPHeadersForDSID", b"")]) # type: ignore
|
||||
util = NSClassFromString("AOSUtilities")
|
||||
|
||||
h = util.retrieveOTPHeadersForDSID_("-2")
|
||||
|
||||
return {
|
||||
"X-Apple-I-MD": str(h["X-Apple-MD"]),
|
||||
"X-Apple-I-MD-M": str(h["X-Apple-MD-M"]),
|
||||
}
|
||||
|
||||
def _generate_remote_anisette(url: str) -> dict:
|
||||
print("Using remote anisette generation: " + url)
|
||||
h = json.loads(requests.get(url, timeout=5).text)
|
||||
return {
|
||||
"X-Apple-I-MD": h["X-Apple-I-MD"],
|
||||
"X-Apple-I-MD-M": h["X-Apple-I-MD-M"],
|
||||
}
|
||||
|
||||
def generate_anisette_headers() -> dict:
|
||||
if isinstance(ANISETTE, str) and ANISETTE.startswith("http"):
|
||||
a = _generate_remote_anisette(ANISETTE)
|
||||
else:
|
||||
a =_generate_local_anisette()
|
||||
|
||||
a.update(_generate_meta_headers(user_id=USER_ID, device_id=DEVICE_ID))
|
||||
return a
|
||||
|
||||
|
||||
def authenticated_request(parameters) -> dict:
|
||||
body = {
|
||||
"Header": {
|
||||
"Version": "1.0.1",
|
||||
},
|
||||
"Request": {
|
||||
"cpd": anisette.generate_cpd(),
|
||||
"cpd": _generate_cpd(),
|
||||
},
|
||||
}
|
||||
body["Request"].update(parameters)
|
||||
|
@ -305,11 +176,10 @@ def authenticated_request(parameters, anisette: Anisette) -> dict:
|
|||
"Content-Type": "text/x-xml-plist",
|
||||
"Accept": "*/*",
|
||||
"User-Agent": "akd/1.0 CFNetwork/978.0.7 Darwin/18.7.0",
|
||||
"X-MMe-Client-Info": anisette.client,
|
||||
"X-MMe-Client-Info": build_client(emulated_app="Xcode"),
|
||||
}
|
||||
|
||||
resp = requests.post(
|
||||
# "https://17.32.194.2/grandslam/GsService2",
|
||||
"https://gsa.apple.com/grandslam/GsService2",
|
||||
headers=headers,
|
||||
data=plist.dumps(body),
|
||||
|
@ -361,7 +231,7 @@ def decrypt_cbc(usr: srp.User, data: bytes) -> bytes:
|
|||
return padder.update(data) + padder.finalize()
|
||||
|
||||
|
||||
def trusted_second_factor(dsid, idms_token, anisette: Anisette):
|
||||
def trusted_second_factor(dsid, idms_token):
|
||||
identity_token = b64encode((dsid + ":" + idms_token).encode()).decode()
|
||||
|
||||
headers = {
|
||||
|
@ -370,9 +240,12 @@ def trusted_second_factor(dsid, idms_token, anisette: Anisette):
|
|||
"Accept": "text/x-xml-plist",
|
||||
"Accept-Language": "en-us",
|
||||
"X-Apple-Identity-Token": identity_token,
|
||||
"X-Apple-App-Info": "com.apple.gs.xcode.auth",
|
||||
"X-Xcode-Version": "11.2 (11B41)",
|
||||
"X-Mme-Client-Info": build_client(emulated_app="Xcode")
|
||||
}
|
||||
|
||||
headers.update(anisette.generate_headers(client_info=True))
|
||||
headers.update(generate_anisette_headers())
|
||||
|
||||
# This will trigger the 2FA prompt on trusted devices
|
||||
# We don't care about the response, it's just some HTML with a form for entering the code
|
||||
|
@ -403,7 +276,7 @@ def trusted_second_factor(dsid, idms_token, anisette: Anisette):
|
|||
print("2FA successful")
|
||||
|
||||
|
||||
def sms_second_factor(dsid, idms_token, anisette: Anisette):
|
||||
def sms_second_factor(dsid, idms_token):
|
||||
# TODO: Figure out how to make SMS 2FA work correctly
|
||||
raise NotImplementedError("SMS 2FA is not yet implemented")
|
||||
identity_token = b64encode((dsid + ":" + idms_token).encode()).decode()
|
||||
|
@ -415,9 +288,12 @@ def sms_second_factor(dsid, idms_token, anisette: Anisette):
|
|||
"Accept": "application/x-buddyml",
|
||||
"Accept-Language": "en-us",
|
||||
"X-Apple-Identity-Token": identity_token,
|
||||
"X-Apple-App-Info": "com.apple.gs.xcode.auth",
|
||||
"X-Xcode-Version": "11.2 (11B41)",
|
||||
"X-Mme-Client-Info": build_client(emulated_app="Xcode")
|
||||
}
|
||||
|
||||
headers.update(anisette.generate_headers(client_info=True))
|
||||
headers.update(generate_anisette_headers())
|
||||
|
||||
body = {"serverInfo": {"phoneNumber.id": "1"}}
|
||||
|
||||
|
@ -457,7 +333,7 @@ def sms_second_factor(dsid, idms_token, anisette: Anisette):
|
|||
# print("2FA successful")
|
||||
|
||||
|
||||
def authenticate(username, password, anisette: Anisette):
|
||||
def authenticate(username, password):
|
||||
# Password is None as we'll provide it later
|
||||
usr = srp.User(username, bytes(), hash_alg=srp.SHA256, ng_type=srp.NG_2048)
|
||||
_, A = usr.start_authentication()
|
||||
|
@ -469,8 +345,7 @@ def authenticate(username, password, anisette: Anisette):
|
|||
# "ps": ["s2k"],
|
||||
"u": username,
|
||||
"o": "init",
|
||||
},
|
||||
anisette,
|
||||
}
|
||||
)
|
||||
|
||||
# Check for an error code
|
||||
|
@ -497,8 +372,7 @@ def authenticate(username, password, anisette: Anisette):
|
|||
"M1": M,
|
||||
"u": username,
|
||||
"o": "complete",
|
||||
},
|
||||
anisette,
|
||||
}
|
||||
)
|
||||
|
||||
if check_error(r):
|
||||
|
@ -524,11 +398,11 @@ def authenticate(username, password, anisette: Anisette):
|
|||
for k, v in spd.items():
|
||||
if isinstance(v, bytes):
|
||||
spd[k] = b64encode(v).decode()
|
||||
trusted_second_factor(spd["adsid"], spd["GsIdmsToken"], anisette)
|
||||
return authenticate(username, password, anisette)
|
||||
trusted_second_factor(spd["adsid"], spd["GsIdmsToken"])
|
||||
return authenticate(username, password)
|
||||
elif "au" in r["Status"] and r["Status"]["au"] == "secondaryAuth":
|
||||
print("SMS authentication required")
|
||||
sms_second_factor(spd["adsid"], spd["GsIdmsToken"], anisette)
|
||||
sms_second_factor(spd["adsid"], spd["GsIdmsToken"])
|
||||
elif "au" in r["Status"]:
|
||||
print(f"Unknown auth value {r['Status']['au']}")
|
||||
return
|
||||
|
|
Loading…
Reference in a new issue