receive already logged in authenticator

This commit is contained in:
əlemi 2022-04-06 21:29:07 +02:00
parent a75f0ff9e4
commit 8f04b34092
No known key found for this signature in database
GPG key ID: BBCBFE5D7244634E

View file

@ -12,7 +12,7 @@ from typing import Dict, List, Callable, Type, Optional, Tuple, AsyncIterator, A
from .dispatcher import Dispatcher from .dispatcher import Dispatcher
from .mc.packet import Packet from .mc.packet import Packet
from .mc.auth import AuthInterface, AuthException, MojangToken, MicrosoftAuthenticator from .mc.auth import AuthInterface, AuthException, MojangAuthenticator, MicrosoftAuthenticator
from .mc.definitions import Dimension, Difficulty, Gamemode, ConnectionState from .mc.definitions import Dimension, Difficulty, Gamemode, ConnectionState
from .mc.proto.status.serverbound import PacketPing, PacketPingStart from .mc.proto.status.serverbound import PacketPing, PacketPingStart
from .mc.proto.status.clientbound import PacketServerInfo, PacketPing as PacketPong from .mc.proto.status.clientbound import PacketServerInfo, PacketPing as PacketPong
@ -39,27 +39,21 @@ class MinecraftClient:
host:str host:str
port:int port:int
options:ClientOptions options:ClientOptions
username:str
_authenticator:MicrosoftAuthenticator online_mode:bool
_username:str authenticator:Optional[AuthInterface]
code:Optional[str]
dispatcher : Dispatcher dispatcher : Dispatcher
_processing : bool logger : logging.Logger
_authenticated : bool _authenticated : bool
_processing : bool
_worker : Task _worker : Task
_logger : logging.Logger
def __init__( def __init__(
self, self,
server:str, server:str,
login_code:str = '',
online_mode:bool = True, online_mode:bool = True,
username:str = '', authenticator:AuthInterface=None,
client_id:str = '', # TODO maybe hardcode defaults? username:str = "",
client_secret:str='',
redirect_uri:str='http://localhost',
**kwargs **kwargs
): ):
super().__init__() super().__init__()
@ -73,16 +67,15 @@ class MinecraftClient:
self.options = ClientOptions(**kwargs) self.options = ClientOptions(**kwargs)
self.code = login_code or None # TODO put this directly in the authenticator maybe? self.username = username
self._username = username
self._authenticator = MicrosoftAuthenticator(client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri)
self.online_mode = online_mode self.online_mode = online_mode
self.authenticator = authenticator
self._authenticated = False
self.dispatcher = Dispatcher() self.dispatcher = Dispatcher()
self._processing = False self._processing = False
self._authenticated = False
self._logger = LOGGER.getChild(f"on({self.host}:{self.port})") self.logger = LOGGER.getChild(f"on({self.host}:{self.port})")
@property @property
def connected(self) -> bool: def connected(self) -> bool:
@ -95,15 +88,15 @@ class MinecraftClient:
if self._authenticated: if self._authenticated:
return # Don't spam Auth endpoint! return # Don't spam Auth endpoint!
try: try:
await self._authenticator.validate() # will raise an exc if token is invalid await self.authenticator.validate() # will raise an exc if token is invalid
except AuthException: except AuthException:
if self.code: if self.code:
await self._authenticator.login(self.code) await self.authenticator.login(self.code)
self.code = None self.code = None
self._logger.info("Logged in with OAuth code") self.logger.info("Logged in with OAuth code")
elif self._authenticator.refreshable: elif self.authenticator.refreshable:
await self._authenticator.refresh() await self._authenticator.refresh()
self._logger.warning("Refreshed Token") self.logger.warning("Refreshed Token")
else: else:
raise ValueError("No refreshable auth or code to login") raise ValueError("No refreshable auth or code to login")
self._authenticated = True self._authenticated = True
@ -161,7 +154,7 @@ class MinecraftClient:
async for packet in self.dispatcher.packets(): async for packet in self.dispatcher.packets():
if isinstance(packet, PacketServerInfo): if isinstance(packet, PacketServerInfo):
data = json.loads(packet.response) data = json.loads(packet.response)
self._logger.debug("Server data : %s", json.dumps(data, indent=2)) self.logger.debug("Server data : %s", json.dumps(data, indent=2))
if not ping: if not ping:
break break
ping_id = int(time()) ping_id = int(time())
@ -183,16 +176,16 @@ class MinecraftClient:
await self.dispatcher.write( await self.dispatcher.write(
PacketLoginStart( PacketLoginStart(
self.dispatcher.proto, self.dispatcher.proto,
username=self._authenticator.selectedProfile.name if self.online_mode else self._username username=self.authenticator.selectedProfile.name if self.online_mode else self._username
) )
) )
async for packet in self.dispatcher.packets(): async for packet in self.dispatcher.packets():
if isinstance(packet, PacketEncryptionBegin): if isinstance(packet, PacketEncryptionBegin):
if not self.online_mode: if not self.online_mode:
self._logger.error("Cannot answer Encryption Request in offline mode") self.logger.error("Cannot answer Encryption Request in offline mode")
return False return False
if not self._authenticator: if not self.authenticator:
self._logger.error("No available token to enable encryption") self.logger.error("No available token to enable encryption")
return False return False
secret = encryption.generate_shared_secret() secret = encryption.generate_shared_secret()
token, encrypted_secret = encryption.encrypt_token_and_secret( token, encrypted_secret = encryption.encrypt_token_and_secret(
@ -210,11 +203,11 @@ class MinecraftClient:
) )
) )
except AuthException: except AuthException:
self._logger.error("Could not authenticate with Mojang") self.logger.error("Could not authenticate with Mojang")
self._authenticated = False self._authenticated = False
return False return False
else: else:
self._logger.warning("Server gave an offline-mode serverId but still requested Encryption") self.logger.warning("Server gave an offline-mode serverId but still requested Encryption")
encryption_response = PacketEncryptionResponse( encryption_response = PacketEncryptionResponse(
self.dispatcher.proto, self.dispatcher.proto,
sharedSecret=encrypted_secret, sharedSecret=encrypted_secret,
@ -223,29 +216,29 @@ class MinecraftClient:
await self.dispatcher.write(encryption_response, wait=True) await self.dispatcher.write(encryption_response, wait=True)
self.dispatcher.encrypt(secret) self.dispatcher.encrypt(secret)
elif isinstance(packet, PacketCompress): elif isinstance(packet, PacketCompress):
self._logger.info("Compression enabled") self.logger.info("Compression enabled")
self.dispatcher.compression = packet.threshold self.dispatcher.compression = packet.threshold
elif isinstance(packet, PacketLoginPluginRequest): elif isinstance(packet, PacketLoginPluginRequest):
self._logger.info("Ignoring plugin request") # TODO ? self.logger.info("Ignoring plugin request") # TODO ?
elif isinstance(packet, PacketSuccess): elif isinstance(packet, PacketSuccess):
self._logger.info("Login success, joining world...") self.logger.info("Login success, joining world...")
return True return True
elif isinstance(packet, PacketDisconnect): elif isinstance(packet, PacketDisconnect):
self._logger.error("Kicked while logging in : %s", helpers.parse_chat(packet.reason)) self.logger.error("Kicked while logging in : %s", helpers.parse_chat(packet.reason))
return False return False
return False return False
async def _play(self): async def _play(self):
self.dispatcher.state = ConnectionState.PLAY self.dispatcher.state = ConnectionState.PLAY
async for packet in self.dispatcher.packets(): async for packet in self.dispatcher.packets():
self._logger.debug("[ * ] Processing %s", packet.__class__.__name__) self.logger.debug("[ * ] Processing %s", packet.__class__.__name__)
if isinstance(packet, PacketSetCompression): if isinstance(packet, PacketSetCompression):
self._logger.info("Compression updated") self.logger.info("Compression updated")
self.dispatcher.compression = packet.threshold self.dispatcher.compression = packet.threshold
elif isinstance(packet, PacketKeepAlive): elif isinstance(packet, PacketKeepAlive):
if self.options.keep_alive: if self.options.keep_alive:
keep_alive_packet = PacketKeepAliveResponse(340, keepAliveId=packet.keepAliveId) keep_alive_packet = PacketKeepAliveResponse(340, keepAliveId=packet.keepAliveId)
await self.dispatcher.write(keep_alive_packet) await self.dispatcher.write(keep_alive_packet)
elif isinstance(packet, PacketKickDisconnect): elif isinstance(packet, PacketKickDisconnect):
self._logger.error("Kicked while in game : %s", helpers.parse_chat(packet.reason)) self.logger.error("Kicked while in game : %s", helpers.parse_chat(packet.reason))
break break