better auth checking

This commit is contained in:
əlemi 2021-11-11 13:00:17 +01:00
parent d8dc04e663
commit 699536fd78
2 changed files with 31 additions and 14 deletions

View file

@ -8,7 +8,7 @@ from typing import Dict, List, Callable, Type, Optional, Tuple
from .dispatcher import Dispatcher, ConnectionState
from .mc.mctypes import VarInt
from .mc.packet import Packet
from .mc.identity import Token
from .mc.identity import Token, AuthException
from .mc import proto, encryption
LOGGER = logging.getLogger(__name__)
@ -34,6 +34,7 @@ _STATE_REGS = {
class Client:
host:str
port:int
options:dict
username:Optional[str]
password:Optional[str]
@ -41,6 +42,7 @@ class Client:
dispatcher : Dispatcher
_processing : bool
_authenticated : bool
_worker : Task
_packet_callbacks : Dict[ConnectionState, Dict[Packet, List[Callable]]]
@ -50,12 +52,14 @@ class Client:
self,
host:str,
port:int,
options:dict = None,
username:Optional[str] = None,
password:Optional[str] = None,
token:Optional[Token] = None,
):
self.host = host
self.port = port
self.options = options or {}
self.token = token
self.username = username
@ -63,6 +67,7 @@ class Client:
self.dispatcher = Dispatcher()
self._processing = False
self._authenticated = False
self._packet_callbacks = {}
@ -97,15 +102,12 @@ class Client:
self.token = await Token.authenticate(self.username, self.password)
self._logger.info("Authenticated from credentials")
return True
return False
raise AuthException("No token or credentials provided")
try:
await self.token.validate() # will raise an exc if token is invalid
except Exception: # idk TODO
try:
except AuthException:
await self.token.refresh()
self._logger.warning("Refreshed Token")
except Exception:
return False
return True
async def change_server(self, server:str):
@ -129,10 +131,12 @@ class Client:
await self.start()
try:
while True: # TODO don't busywait even if it doesn't matter much
while self._processing: # TODO don't busywait even if it doesn't matter much
await asyncio.sleep(5)
except KeyboardInterrupt:
self._logger.info("Received SIGINT, stopping...")
else:
self._logger.warning("Client terminating...")
await self.stop()
@ -150,19 +154,25 @@ class Client:
async def _client_worker(self):
while self._processing:
if not await self.authenticate():
raise Exception("Token not refreshable or credentials invalid") # TODO!
try:
await self.authenticate()
except AuthException:
self._logger.error("Token not refreshable or credentials invalid")
await self.stop(block=False)
try:
await self.dispatcher.connect(self.host, self.port)
for packet in self._handshake():
await self.dispatcher.write(packet)
self.dispatcher.state = ConnectionState.LOGIN
await self._process_packets()
except AuthException as e: # TODO maybe tell what went wrong
self._authenticated = False
self._logger.error("Authentication exception")
except ConnectionRefusedError:
self._logger.error("Server rejected connection")
except Exception:
self._logger.exception("Exception in Client connection")
await asyncio.sleep(2)
await asyncio.sleep(self.options["rctime"])
def _handshake(self, force:bool=False) -> Tuple[Packet, Packet]: # TODO make this fancier! poll for version and status first
return ( proto.handshaking.serverbound.PacketSetProtocol(

View file

@ -1,12 +1,16 @@
"""Minecraft identity utilities."""
import json
import uuid
import logging
from dataclasses import dataclass
from typing import Optional
import aiohttp
class AuthException(Exception):
pass
@dataclass
class Profile:
id : str
@ -96,6 +100,9 @@ class Token:
async def _post(cls, endpoint:str, data:dict) -> dict:
async with aiohttp.ClientSession() as sess:
async with sess.post(endpoint, headers=cls.HEADERS, data=json.dumps(data).encode('utf-8')) as res:
# TODO parse and raise exceptions
return await res.json(content_type=None)
data = await res.json(content_type=None)
logging.info(f"Auth request | {data}")
if res.status != 200:
raise AuthException(f"Action '{endpoint.rsplit('/',1)[1]}' did not succeed")
return data