client auth flow changes for new MS authentication
This commit is contained in:
parent
b6e38660c3
commit
3cb6760f10
1 changed files with 32 additions and 38 deletions
|
@ -12,7 +12,7 @@ from typing import Dict, List, Callable, Type, Optional, Tuple, AsyncIterator
|
||||||
from .dispatcher import Dispatcher
|
from .dispatcher import Dispatcher
|
||||||
from .traits import CallbacksHolder, Runnable
|
from .traits import CallbacksHolder, Runnable
|
||||||
from .mc.packet import Packet
|
from .mc.packet import Packet
|
||||||
from .mc.auth import AuthInterface, AuthException, MojangToken
|
from .mc.auth import AuthInterface, AuthException, MojangToken, MicrosoftAuthenticator
|
||||||
from .mc.definitions import Dimension, Difficulty, Gamemode, ConnectionState
|
from .mc.definitions import Dimension, Difficulty, Gamemode, ConnectionState
|
||||||
from .mc.proto.handshaking.serverbound import PacketSetProtocol
|
from .mc.proto.handshaking.serverbound import PacketSetProtocol
|
||||||
from .mc.proto.play.serverbound import PacketKeepAlive as PacketKeepAliveResponse
|
from .mc.proto.play.serverbound import PacketKeepAlive as PacketKeepAliveResponse
|
||||||
|
@ -42,9 +42,8 @@ class MinecraftClient(CallbacksHolder, Runnable):
|
||||||
port:int
|
port:int
|
||||||
options:ClientOptions
|
options:ClientOptions
|
||||||
|
|
||||||
username:Optional[str]
|
_authenticator:AuthInterface
|
||||||
password:Optional[str]
|
code:str
|
||||||
token:Optional[AuthInterface]
|
|
||||||
|
|
||||||
dispatcher : Dispatcher
|
dispatcher : Dispatcher
|
||||||
_processing : bool
|
_processing : bool
|
||||||
|
@ -56,28 +55,29 @@ class MinecraftClient(CallbacksHolder, Runnable):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
host:str,
|
server:str,
|
||||||
port:int = 25565,
|
code:str,
|
||||||
username:Optional[str] = None,
|
|
||||||
password:Optional[str] = None,
|
|
||||||
token:Optional[AuthInterface] = None,
|
|
||||||
online_mode:bool = True,
|
online_mode:bool = True,
|
||||||
|
client_id:str = '', # TODO maybe hardcode defaults?
|
||||||
|
client_secret:str='',
|
||||||
|
redirect_uri:str='http://localhost',
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.host = host
|
if ":" in server:
|
||||||
self.port = port
|
_host, _port = server.split(":", 1)
|
||||||
|
self.host = _host.strip()
|
||||||
|
self.port = int(_port)
|
||||||
|
else:
|
||||||
|
self.host = server.strip()
|
||||||
|
self.port = 25565
|
||||||
|
|
||||||
self.options = ClientOptions(**kwargs)
|
self.options = ClientOptions(**kwargs)
|
||||||
|
|
||||||
self.token = token
|
self.code = code
|
||||||
self.username = username
|
self._authenticator = MicrosoftAuthenticator(client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri)
|
||||||
self.password = password
|
|
||||||
self.online_mode = online_mode
|
self.online_mode = online_mode
|
||||||
|
|
||||||
if self.online_mode and not self.token and not self.username and not self.password:
|
|
||||||
raise ValueError("Cannot instantiate an online-mode client without token or credentials")
|
|
||||||
|
|
||||||
self.dispatcher = Dispatcher()
|
self.dispatcher = Dispatcher()
|
||||||
self._processing = False
|
self._processing = False
|
||||||
self._authenticated = False
|
self._authenticated = False
|
||||||
|
@ -113,24 +113,17 @@ class MinecraftClient(CallbacksHolder, Runnable):
|
||||||
async def authenticate(self):
|
async def authenticate(self):
|
||||||
if self._authenticated:
|
if self._authenticated:
|
||||||
return # Don't spam Auth endpoint!
|
return # Don't spam Auth endpoint!
|
||||||
if self.token:
|
|
||||||
try:
|
try:
|
||||||
await self.token.validate() # will raise an exc if token is invalid
|
await self._authenticator.validate() # will raise an exc if token is invalid
|
||||||
self._authenticated = True
|
self._authenticated = True
|
||||||
return
|
return
|
||||||
except AuthException:
|
except AuthException:
|
||||||
try:
|
if self._authenticator.refreshable:
|
||||||
await self.token.refresh()
|
await self._authenticator.refresh()
|
||||||
self._logger.warning("Refreshed Token")
|
self._logger.warning("Refreshed Token")
|
||||||
self._authenticated = True
|
else:
|
||||||
return
|
await self._authenticator.login(self.code)
|
||||||
except AuthException as e:
|
self._logger.info("Logged in with OAuth code")
|
||||||
self._logger.warning("Token is not refreshable : %s", e.message)
|
|
||||||
if not self.username and not self.password:
|
|
||||||
raise e # we don't have credentials to make a new token, nothing we can really do here
|
|
||||||
if self.username and self.password:
|
|
||||||
self.token = await MojangToken.login(self.username, self.password)
|
|
||||||
self._logger.info("Authenticated from credentials")
|
|
||||||
self._authenticated = True
|
self._authenticated = True
|
||||||
return
|
return
|
||||||
raise ValueError("No token or credentials to authenticate") # This should never happen
|
raise ValueError("No token or credentials to authenticate") # This should never happen
|
||||||
|
@ -156,6 +149,7 @@ class MinecraftClient(CallbacksHolder, Runnable):
|
||||||
await super().start()
|
await super().start()
|
||||||
if self.started:
|
if self.started:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._processing = True
|
self._processing = True
|
||||||
self._worker = asyncio.get_event_loop().create_task(self._client_worker())
|
self._worker = asyncio.get_event_loop().create_task(self._client_worker())
|
||||||
self._logger.info("Minecraft client started")
|
self._logger.info("Minecraft client started")
|
||||||
|
@ -218,7 +212,7 @@ class MinecraftClient(CallbacksHolder, Runnable):
|
||||||
await self.dispatcher.write(
|
await self.dispatcher.write(
|
||||||
PacketLoginStart(
|
PacketLoginStart(
|
||||||
340,
|
340,
|
||||||
username=self.token.selectedProfile.name if self.online_mode and self.token else self.username
|
username=self._authenticator.selectedProfile.name if self.online_mode else self.code # TODO this is awful
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
@ -230,7 +224,7 @@ class MinecraftClient(CallbacksHolder, Runnable):
|
||||||
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.token:
|
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()
|
||||||
|
@ -241,7 +235,7 @@ class MinecraftClient(CallbacksHolder, Runnable):
|
||||||
)
|
)
|
||||||
if packet.serverId != '-':
|
if packet.serverId != '-':
|
||||||
try:
|
try:
|
||||||
await self.token.join(
|
await self._authenticator.join(
|
||||||
encryption.generate_verification_hash(
|
encryption.generate_verification_hash(
|
||||||
packet.serverId,
|
packet.serverId,
|
||||||
secret,
|
secret,
|
||||||
|
|
Loading…
Reference in a new issue