Clear the cookie on a 5027 from login
This commit is contained in:
1 parent
6929633093
commit
fee022b5a4
2 files changed
+26
-21
No files matched your search
+3
-1
@@ -8,6 +8,8 @@ from enum import Enum, auto
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import Any, Dict, Literal, NewType, TYPE_CHECKING
|
from typing import Any, Dict, Literal, NewType, TYPE_CHECKING
|
||||||
|
|
||||||
|
from yarl import URL
|
||||||
|
|
||||||
from version import __version__
|
from version import __version__
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -59,7 +61,7 @@ MAX_WEBSOCKETS = 8
|
|||||||
WS_TOPICS_LIMIT = 50
|
WS_TOPICS_LIMIT = 50
|
||||||
# Misc
|
# Misc
|
||||||
DEFAULT_LANG = "English"
|
DEFAULT_LANG = "English"
|
||||||
BASE_URL = "https://twitch.tv"
|
BASE_URL = URL("https://twitch.tv")
|
||||||
CLIENT_ID = "kd1unb4b3q4t58fwlpcbzcbnm76a8fp"
|
CLIENT_ID = "kd1unb4b3q4t58fwlpcbzcbnm76a8fp"
|
||||||
# CLIENT_ID = "uo6dggojyb8d6soh92zknwmi5ej1q2"
|
# CLIENT_ID = "uo6dggojyb8d6soh92zknwmi5ej1q2"
|
||||||
USER_AGENT = (
|
USER_AGENT = (
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ class _AuthState:
|
|||||||
and datetime.now(timezone.utc) >= self.integrity_expires
|
and datetime.now(timezone.utc) >= self.integrity_expires
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _hasattrs(self, *attrs: str) -> bool:
|
||||||
|
return all(hasattr(self, attr) for attr in attrs)
|
||||||
|
|
||||||
def _delattrs(self, *attrs: str) -> None:
|
def _delattrs(self, *attrs: str) -> None:
|
||||||
for attr in attrs:
|
for attr in attrs:
|
||||||
if hasattr(self, attr):
|
if hasattr(self, attr):
|
||||||
@@ -130,8 +133,12 @@ class _AuthState:
|
|||||||
if "error_code" in login_response:
|
if "error_code" in login_response:
|
||||||
error_code: int = login_response["error_code"]
|
error_code: int = login_response["error_code"]
|
||||||
logger.debug(f"Login error code: {error_code}")
|
logger.debug(f"Login error code: {error_code}")
|
||||||
if error_code == 1000:
|
if error_code in (1000, 5027):
|
||||||
# we've failed bois
|
# we've failed bois
|
||||||
|
session = await self._twitch.get_session()
|
||||||
|
jar = cast(aiohttp.CookieJar, session.cookie_jar)
|
||||||
|
assert BASE_URL.host is not None
|
||||||
|
jar.clear_domain(BASE_URL.host)
|
||||||
logger.debug("Login failed due to CAPTCHA")
|
logger.debug("Login failed due to CAPTCHA")
|
||||||
raise CaptchaRequired()
|
raise CaptchaRequired()
|
||||||
elif error_code == 3001:
|
elif error_code == 3001:
|
||||||
@@ -204,28 +211,25 @@ class _AuthState:
|
|||||||
async def _validate(self):
|
async def _validate(self):
|
||||||
if not hasattr(self, "session_id"):
|
if not hasattr(self, "session_id"):
|
||||||
self.session_id = create_nonce(CHARS_HEX_LOWER, 16)
|
self.session_id = create_nonce(CHARS_HEX_LOWER, 16)
|
||||||
if not (hasattr(self, "client_version") and hasattr(self, "device_id")):
|
if not self._hasattrs("client_version", "device_id", "access_token", "user_id"):
|
||||||
|
session = await self._twitch.get_session()
|
||||||
|
jar = cast(aiohttp.CookieJar, session.cookie_jar)
|
||||||
|
if not self._hasattrs("client_version", "device_id"):
|
||||||
async with self._twitch.request("GET", BASE_URL) as response:
|
async with self._twitch.request("GET", BASE_URL) as response:
|
||||||
match = re.search(r'twilightBuildID="([-a-z0-9]+)"', await response.text("utf8"))
|
match = re.search(r'twilightBuildID="([-a-z0-9]+)"', await response.text("utf8"))
|
||||||
if match is None:
|
if match is None:
|
||||||
raise MinerException("Unable to extract client_version")
|
raise MinerException("Unable to extract client_version")
|
||||||
self.client_version = match.group(1)
|
self.client_version = match.group(1)
|
||||||
# doing the request ends up setting the "unique_id" value in the cookie
|
# doing the request ends up setting the "unique_id" value in the cookie
|
||||||
session = await self._twitch.get_session()
|
cookie = jar.filter_cookies(BASE_URL)
|
||||||
jar = cast(aiohttp.CookieJar, session.cookie_jar)
|
|
||||||
cookie = jar.filter_cookies(URL(BASE_URL))
|
|
||||||
self.device_id = cookie["unique_id"].value
|
self.device_id = cookie["unique_id"].value
|
||||||
if not (hasattr(self, "access_token") and hasattr(self, "user_id")):
|
if not self._hasattrs("access_token", "user_id"):
|
||||||
# looks like we're missing something
|
# looks like we're missing something
|
||||||
login_form: LoginForm = self._twitch.gui.login
|
login_form: LoginForm = self._twitch.gui.login
|
||||||
logger.debug("Checking login")
|
logger.debug("Checking login")
|
||||||
login_form.update(_("gui", "login", "logging_in"), None)
|
login_form.update(_("gui", "login", "logging_in"), None)
|
||||||
session = await self._twitch.get_session()
|
|
||||||
jar = cast(aiohttp.CookieJar, session.cookie_jar)
|
|
||||||
url = URL(BASE_URL)
|
|
||||||
assert url.host is not None
|
|
||||||
for attempt in range(2):
|
for attempt in range(2):
|
||||||
cookie = jar.filter_cookies(url)
|
cookie = jar.filter_cookies(BASE_URL)
|
||||||
if "auth-token" not in cookie:
|
if "auth-token" not in cookie:
|
||||||
self.access_token = await self._login()
|
self.access_token = await self._login()
|
||||||
cookie["auth-token"] = self.access_token
|
cookie["auth-token"] = self.access_token
|
||||||
@@ -242,7 +246,8 @@ class _AuthState:
|
|||||||
if status == 401:
|
if status == 401:
|
||||||
# the access token we have is invalid - clear the cookie and reauth
|
# the access token we have is invalid - clear the cookie and reauth
|
||||||
logger.debug("Restored session is invalid")
|
logger.debug("Restored session is invalid")
|
||||||
jar.clear_domain(url.host)
|
assert BASE_URL.host is not None
|
||||||
|
jar.clear_domain(BASE_URL.host)
|
||||||
continue
|
continue
|
||||||
elif status == 200:
|
elif status == 200:
|
||||||
validate_response = await response.json()
|
validate_response = await response.json()
|
||||||
@@ -254,9 +259,9 @@ class _AuthState:
|
|||||||
logger.debug(f"Login successful, user ID: {self.user_id}")
|
logger.debug(f"Login successful, user ID: {self.user_id}")
|
||||||
login_form.update(_("gui", "login", "logged_in"), self.user_id)
|
login_form.update(_("gui", "login", "logged_in"), self.user_id)
|
||||||
# update our cookie and save it
|
# update our cookie and save it
|
||||||
jar.update_cookies(cookie, url)
|
jar.update_cookies(cookie, BASE_URL)
|
||||||
jar.save(COOKIES_PATH)
|
jar.save(COOKIES_PATH)
|
||||||
if not hasattr(self, "integrity_token") or self.integrity_expired:
|
if not self._hasattrs("integrity_token") or self.integrity_expired:
|
||||||
async with self._twitch.request(
|
async with self._twitch.request(
|
||||||
"POST",
|
"POST",
|
||||||
"https://gql.twitch.tv/integrity",
|
"https://gql.twitch.tv/integrity",
|
||||||
@@ -272,17 +277,15 @@ class _AuthState:
|
|||||||
self.integrity_expires = ((expiration - now) * 0.9) + now
|
self.integrity_expires = ((expiration - now) * 0.9) + now
|
||||||
# verify the integrity token's contents for the "is_bad_bot" flag
|
# verify the integrity token's contents for the "is_bad_bot" flag
|
||||||
stripped_token: str = self.integrity_token.split('.')[2] + "=="
|
stripped_token: str = self.integrity_token.split('.')[2] + "=="
|
||||||
messy_json: str = urlsafe_b64decode(
|
messy_json: str = urlsafe_b64decode(stripped_token.encode()).decode(errors="ignore")
|
||||||
stripped_token.encode()
|
|
||||||
).decode(errors="ignore").replace('\n', '')
|
|
||||||
match = re.search(r'(.+)(?<="}).+$', messy_json)
|
match = re.search(r'(.+)(?<="}).+$', messy_json)
|
||||||
if match is None:
|
if match is None:
|
||||||
raise MinerException("Unable to parse the integrity token")
|
raise MinerException("Unable to parse the integrity token")
|
||||||
decoded_header: JsonType = json.loads(match.group(1))
|
decoded_header: JsonType = json.loads(match.group(1))
|
||||||
if decoded_header.get("is_bad_bot", "false") != "false":
|
if decoded_header.get("is_bad_bot", "false") != "false":
|
||||||
self._twitch.print(
|
self._twitch.print(
|
||||||
"Twitch has detected this miner as a \"Bad Bot\", and may try to stop you "
|
"Twitch has detected this miner as a \"Bad Bot\". "
|
||||||
"from claiming drops. You're proceeding at your own risk!"
|
"You're proceeding at your own risk!"
|
||||||
)
|
)
|
||||||
await asyncio.sleep(8)
|
await asyncio.sleep(8)
|
||||||
self._logged_in.set()
|
self._logged_in.set()
|
||||||
@@ -989,7 +992,7 @@ class Twitch:
|
|||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def request(
|
async def request(
|
||||||
self, method: str, url: str, *, invalidate_after: datetime | None = None, **kwargs
|
self, method: str, url: URL | str, *, invalidate_after: datetime | None = None, **kwargs
|
||||||
) -> abc.AsyncIterator[aiohttp.ClientResponse]:
|
) -> abc.AsyncIterator[aiohttp.ClientResponse]:
|
||||||
session = await self.get_session()
|
session = await self.get_session()
|
||||||
method = method.upper()
|
method = method.upper()
|
||||||
|
|||||||
Reference in new issue
Block a user