|
|
@ -1710,23 +1710,24 @@ class TwitterAPI():
|
|
|
|
|
|
|
|
|
|
|
|
@cache(maxage=365*86400, keyarg=1)
|
|
|
|
@cache(maxage=365*86400, keyarg=1)
|
|
|
|
def _login_impl(extr, username, password):
|
|
|
|
def _login_impl(extr, username, password):
|
|
|
|
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
import random
|
|
|
|
import random
|
|
|
|
|
|
|
|
|
|
|
|
if re.fullmatch(r"[\w.%+-]+@[\w.-]+\.\w{2,}", username):
|
|
|
|
def process(data, params=None):
|
|
|
|
extr.log.warning(
|
|
|
|
response = extr.request(
|
|
|
|
"Login with email is no longer possible. "
|
|
|
|
url, params=params, headers=headers, json=data,
|
|
|
|
"You need to provide your username or phone number instead.")
|
|
|
|
method="POST", fatal=None)
|
|
|
|
|
|
|
|
|
|
|
|
def process(response):
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
data = response.json()
|
|
|
|
data = response.json()
|
|
|
|
except ValueError:
|
|
|
|
except ValueError:
|
|
|
|
data = {"errors": ({"message": "Invalid response"},)}
|
|
|
|
data = {"errors": ({"message": "Invalid response"},)}
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
if response.status_code < 400:
|
|
|
|
if response.status_code < 400:
|
|
|
|
return data["flow_token"]
|
|
|
|
try:
|
|
|
|
|
|
|
|
return (data["flow_token"],
|
|
|
|
|
|
|
|
data["subtasks"][0]["subtask_id"])
|
|
|
|
|
|
|
|
except LookupError:
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
errors = []
|
|
|
|
errors = []
|
|
|
|
for error in data.get("errors") or ():
|
|
|
|
for error in data.get("errors") or ():
|
|
|
@ -1735,9 +1736,13 @@ def _login_impl(extr, username, password):
|
|
|
|
extr.log.debug(response.text)
|
|
|
|
extr.log.debug(response.text)
|
|
|
|
raise exception.AuthenticationError(", ".join(errors))
|
|
|
|
raise exception.AuthenticationError(", ".join(errors))
|
|
|
|
|
|
|
|
|
|
|
|
extr.cookies.clear()
|
|
|
|
cookies = extr.cookies
|
|
|
|
|
|
|
|
cookies.clear()
|
|
|
|
api = TwitterAPI(extr)
|
|
|
|
api = TwitterAPI(extr)
|
|
|
|
api._authenticate_guest()
|
|
|
|
api._authenticate_guest()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
url = "https://api.twitter.com/1.1/onboarding/task.json"
|
|
|
|
|
|
|
|
params = {"flow_name": "login"}
|
|
|
|
headers = api.headers
|
|
|
|
headers = api.headers
|
|
|
|
|
|
|
|
|
|
|
|
extr.log.info("Logging in as %s", username)
|
|
|
|
extr.log.info("Logging in as %s", username)
|
|
|
@ -1794,31 +1799,18 @@ def _login_impl(extr, username, password):
|
|
|
|
"web_modal": 1,
|
|
|
|
"web_modal": 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
url = "https://api.twitter.com/1.1/onboarding/task.json?flow_name=login"
|
|
|
|
|
|
|
|
response = extr.request(url, method="POST", headers=headers, json=data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data = {
|
|
|
|
flow_token, subtask = process(data, params)
|
|
|
|
"flow_token": process(response),
|
|
|
|
while not cookies.get("auth_token"):
|
|
|
|
"subtask_inputs": [
|
|
|
|
if subtask == "LoginJsInstrumentationSubtask":
|
|
|
|
{
|
|
|
|
data = {
|
|
|
|
"subtask_id": "LoginJsInstrumentationSubtask",
|
|
|
|
|
|
|
|
"js_instrumentation": {
|
|
|
|
"js_instrumentation": {
|
|
|
|
"response": "{}",
|
|
|
|
"response": "{}",
|
|
|
|
"link": "next_link",
|
|
|
|
"link": "next_link",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
],
|
|
|
|
elif subtask == "LoginEnterUserIdentifierSSO":
|
|
|
|
}
|
|
|
|
data = {
|
|
|
|
url = "https://api.twitter.com/1.1/onboarding/task.json"
|
|
|
|
|
|
|
|
response = extr.request(
|
|
|
|
|
|
|
|
url, method="POST", headers=headers, json=data, fatal=None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# username
|
|
|
|
|
|
|
|
data = {
|
|
|
|
|
|
|
|
"flow_token": process(response),
|
|
|
|
|
|
|
|
"subtask_inputs": [
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"subtask_id": "LoginEnterUserIdentifierSSO",
|
|
|
|
|
|
|
|
"settings_list": {
|
|
|
|
"settings_list": {
|
|
|
|
"setting_responses": [
|
|
|
|
"setting_responses": [
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -1830,48 +1822,61 @@ def _login_impl(extr, username, password):
|
|
|
|
],
|
|
|
|
],
|
|
|
|
"link": "next_link",
|
|
|
|
"link": "next_link",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
],
|
|
|
|
elif subtask == "LoginEnterPassword":
|
|
|
|
}
|
|
|
|
data = {
|
|
|
|
# url = "https://api.twitter.com/1.1/onboarding/task.json"
|
|
|
|
|
|
|
|
extr.sleep(random.uniform(2.0, 4.0), "login (username)")
|
|
|
|
|
|
|
|
response = extr.request(
|
|
|
|
|
|
|
|
url, method="POST", headers=headers, json=data, fatal=None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# password
|
|
|
|
|
|
|
|
data = {
|
|
|
|
|
|
|
|
"flow_token": process(response),
|
|
|
|
|
|
|
|
"subtask_inputs": [
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"subtask_id": "LoginEnterPassword",
|
|
|
|
|
|
|
|
"enter_password": {
|
|
|
|
"enter_password": {
|
|
|
|
"password": password,
|
|
|
|
"password": password,
|
|
|
|
"link": "next_link",
|
|
|
|
"link": "next_link",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
],
|
|
|
|
elif subtask == "LoginEnterAlternateIdentifierSubtask":
|
|
|
|
}
|
|
|
|
alt = extr.input(
|
|
|
|
# url = "https://api.twitter.com/1.1/onboarding/task.json"
|
|
|
|
"Alternate Identifier (username, email, phone number): ")
|
|
|
|
extr.sleep(random.uniform(2.0, 4.0), "login (password)")
|
|
|
|
data = {
|
|
|
|
response = extr.request(
|
|
|
|
"enter_text": {
|
|
|
|
url, method="POST", headers=headers, json=data, fatal=None)
|
|
|
|
"text": alt,
|
|
|
|
|
|
|
|
"link": "next_link",
|
|
|
|
# account duplication check ?
|
|
|
|
},
|
|
|
|
data = {
|
|
|
|
}
|
|
|
|
"flow_token": process(response),
|
|
|
|
elif subtask == "LoginTwoFactorAuthChallenge":
|
|
|
|
"subtask_inputs": [
|
|
|
|
data = {
|
|
|
|
{
|
|
|
|
"enter_text": {
|
|
|
|
"subtask_id": "AccountDuplicationCheck",
|
|
|
|
"text": extr.input("2FA Token: "),
|
|
|
|
|
|
|
|
"link": "next_link",
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
elif subtask == "LoginAcid":
|
|
|
|
|
|
|
|
data = {
|
|
|
|
|
|
|
|
"enter_text": {
|
|
|
|
|
|
|
|
"text": extr.input("Email Verification Code: "),
|
|
|
|
|
|
|
|
"link": "next_link",
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
elif subtask == "AccountDuplicationCheck":
|
|
|
|
|
|
|
|
data = {
|
|
|
|
"check_logged_in_account": {
|
|
|
|
"check_logged_in_account": {
|
|
|
|
"link": "AccountDuplicationCheck_false",
|
|
|
|
"link": "AccountDuplicationCheck_false",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
],
|
|
|
|
elif subtask == "ArkoseLogin":
|
|
|
|
}
|
|
|
|
raise exception.AuthenticationError("Login requires CAPTCHA")
|
|
|
|
# url = "https://api.twitter.com/1.1/onboarding/task.json"
|
|
|
|
elif subtask == "DenyLoginSubtask":
|
|
|
|
response = extr.request(
|
|
|
|
raise exception.AuthenticationError("Login rejected as suspicious")
|
|
|
|
url, method="POST", headers=headers, json=data, fatal=None)
|
|
|
|
elif subtask == "ArkoseLogin":
|
|
|
|
process(response)
|
|
|
|
raise exception.AuthenticationError("No auth token cookie")
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
raise exception.StopExtraction("Unrecognized subtask %s", subtask)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inputs = {"subtask_id": subtask}
|
|
|
|
|
|
|
|
inputs.update(data)
|
|
|
|
|
|
|
|
data = {
|
|
|
|
|
|
|
|
"flow_token": flow_token,
|
|
|
|
|
|
|
|
"subtask_inputs": [inputs],
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extr.sleep(random.uniform(1.0, 3.0), "login ({})".format(subtask))
|
|
|
|
|
|
|
|
flow_token, subtask = process(data)
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
cookie.name: cookie.value
|
|
|
|
cookie.name: cookie.value
|
|
|
|