144 lines
5.4 KiB
Python
144 lines
5.4 KiB
Python
# Based on https://github.com/derrod/twl.py
|
|
# Original Copyright (c) 2020 Rodney
|
|
# The MIT License (MIT)
|
|
|
|
import logging
|
|
import getpass
|
|
import browser_cookie3
|
|
import requests
|
|
|
|
from cookies import save_cookies_to_file
|
|
from twitch_data import get_client_id
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class TwitchLogin:
|
|
def __init__(self):
|
|
self.token = None
|
|
self.login_check_result = False
|
|
self.session = requests.session()
|
|
self.session.headers.update({'Client-ID': get_client_id()})
|
|
self.username = None
|
|
self.user_id = None
|
|
self.email = None
|
|
|
|
def login_flow(self):
|
|
logger.info("You'll have to login to Twitch!")
|
|
|
|
post_data = {
|
|
'client_id': get_client_id(),
|
|
'undelete_user': False,
|
|
'remember_me': True
|
|
}
|
|
|
|
use_backup_flow = False
|
|
|
|
while True:
|
|
self.username = input('Enter Twitch username: ')
|
|
password = getpass.getpass('Enter Twitch password: ')
|
|
|
|
post_data['username'] = self.username
|
|
post_data['password'] = password
|
|
|
|
while True:
|
|
# Try login without 2FA
|
|
login_response = self.send_login_request(post_data)
|
|
|
|
if 'captcha_proof' in login_response:
|
|
post_data['captcha'] = dict(proof=login_response['captcha_proof'])
|
|
|
|
if 'error_code' in login_response:
|
|
err_code = login_response['error_code']
|
|
if err_code == 3011 or err_code == 3012: # missing 2fa token
|
|
if err_code == 3011:
|
|
logger.info('Two factor authentication enabled, please enter token below.')
|
|
else:
|
|
logger.info('Invalid two factor token, please try again.')
|
|
|
|
twofa = input('2FA token: ')
|
|
post_data['authy_token'] = twofa.strip()
|
|
continue
|
|
|
|
elif err_code == 3022 or err_code == 3023: # missing 2fa token
|
|
if err_code == 3022:
|
|
logger.info('Login Verification code required.')
|
|
self.email = login_response['obscured_email']
|
|
else:
|
|
logger.info('Invalid Login Verification code entered, please try again.')
|
|
|
|
twofa = input(f'Please enter the 6-digit code sent to {self.email}: ')
|
|
post_data['twitchguard_code'] = twofa.strip()
|
|
continue
|
|
|
|
elif err_code == 3001: # invalid password
|
|
logger.info('Invalid username or password, please try again.')
|
|
break
|
|
elif err_code == 1000:
|
|
logger.info('Console login unavailable (CAPTCHA solving required).')
|
|
use_backup_flow = True
|
|
break
|
|
else:
|
|
logger.info(f'Unknown error: {login_response}')
|
|
raise NotImplementedError(f'Unknown TwitchAPI error code: {err_code}')
|
|
|
|
if 'access_token' in login_response:
|
|
self.set_token(login_response['access_token'])
|
|
return self.check_login()
|
|
|
|
if use_backup_flow:
|
|
break
|
|
|
|
if use_backup_flow:
|
|
self.set_token(self.login_flow_backup())
|
|
return self.check_login()
|
|
|
|
return False
|
|
|
|
def set_token(self, new_token):
|
|
self.token = new_token
|
|
self.session.headers.update({'Authorization': f'Bearer {self.token}'})
|
|
|
|
def send_login_request(self, json_data):
|
|
r = self.session.post('https://passport.twitch.tv/login', json=json_data)
|
|
j = r.json()
|
|
return j
|
|
|
|
def login_flow_backup(self):
|
|
"""Backup OAuth login flow in case manual captcha solving is required"""
|
|
browser = input("What browser do you use? Chrome (1), Firefox (2), Other (3): ").strip()
|
|
if browser not in ("1", "2"):
|
|
logger.info("Your browser is unsupported, sorry.")
|
|
return None
|
|
|
|
input("Please login inside your browser of choice (NOT incognito mode) and press Enter...")
|
|
logger.info("Loading cookies saved on your computer...")
|
|
twitch_domain = ".twitch.tv"
|
|
if browser == "1": # chrome
|
|
cookie_jar = browser_cookie3.chrome(domain_name=twitch_domain)
|
|
else:
|
|
cookie_jar = browser_cookie3.firefox(domain_name=twitch_domain)
|
|
cookies_dict = requests.utils.dict_from_cookiejar(cookie_jar)
|
|
self.username = cookies_dict.get("login")
|
|
return cookies_dict.get("auth-token")
|
|
|
|
def check_login(self):
|
|
if self.login_check_result:
|
|
return self.login_check_result
|
|
if self.token is None:
|
|
return False
|
|
|
|
r = self.session.get(f'https://api.twitch.tv/helix/users?login={self.username}')
|
|
response = r.json()
|
|
if "data" in response:
|
|
self.login_check_result = True
|
|
self.user_id = response["data"][0]["id"]
|
|
|
|
return self.login_check_result
|
|
|
|
def save_cookies(self):
|
|
cookies_dict = self.session.cookies.get_dict()
|
|
cookies_dict["auth-token"] = self.token
|
|
if "persistent" not in cookies_dict: # saving user id cookies
|
|
cookies_dict["persistent"] = self.user_id
|
|
save_cookies_to_file(cookies_dict)
|