From 2190554f719c59d47ae08ac4554adb2f08d4b745 Mon Sep 17 00:00:00 2001 From: alemi Date: Thu, 16 Feb 2023 18:07:21 +0100 Subject: [PATCH] feat: allow overriding auth and session servers --- aiocraft/mc/auth/interface.py | 25 ++++++++++++++--------- aiocraft/mc/auth/mojang.py | 38 ++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/aiocraft/mc/auth/interface.py b/aiocraft/mc/auth/interface.py index 8518129..b1907e6 100644 --- a/aiocraft/mc/auth/interface.py +++ b/aiocraft/mc/auth/interface.py @@ -26,10 +26,14 @@ class AuthException(Exception): class AuthInterface: accessToken : str selectedProfile : GameProfile + session_server_override : str SESSION_SERVER = "https://sessionserver.mojang.com/session/minecraft" TIMEOUT = aiohttp.ClientTimeout(total=3) + def __init__(self): + raise NotImplementedError + async def login(self) -> 'AuthInterface': raise NotImplementedError @@ -45,9 +49,13 @@ class AuthInterface: def deserialize(self, data:Dict[str, Any]): raise NotImplementedError + @property + def session_server(self) -> str: + return self.session_server_override or self.SESSION_SERVER + async def join(self, server_id) -> dict: return await self._post( - self.SESSION_SERVER + "/join", + self.session_server + "/join", headers={"content-type":"application/json"}, json={ "serverId": server_id, @@ -56,16 +64,14 @@ class AuthInterface: } ) - @classmethod # TODO more love for server side! - async def server_join(cls, username:str, serverId:str, ip:Optional[str] = None): + async def server_join(self, username:str, serverId:str, ip:Optional[str] = None): params = {"username":username, "serverId":serverId} if ip: params["ip"] = ip - return await cls._get(cls.SESSION_SERVER + "/hasJoined", params=params) + return await self._get(self.session_server + "/hasJoined", params=params) - @classmethod - async def _post(cls, endpoint:str, **kwargs) -> Dict[str, Any]: - async with aiohttp.ClientSession(timeout=cls.TIMEOUT) as session: + async def _post(self, endpoint:str, **kwargs) -> Dict[str, Any]: + async with aiohttp.ClientSession(timeout=self.TIMEOUT) as session: try: async with session.post(endpoint, **kwargs) as res: try: @@ -79,9 +85,8 @@ class AuthInterface: except TimeoutError: raise AuthException(endpoint, 0, {"error": "request timed out"}, kwargs) - @classmethod - async def _get(cls, endpoint:str, **kwargs) -> Dict[str, Any]: - async with aiohttp.ClientSession(timeout=cls.TIMEOUT) as session: + async def _get(self, endpoint:str, **kwargs) -> Dict[str, Any]: + async with aiohttp.ClientSession(timeout=self.TIMEOUT) as session: try: async with session.get(endpoint, **kwargs) as res: try: diff --git a/aiocraft/mc/auth/mojang.py b/aiocraft/mc/auth/mojang.py index 4a235da..0ffb35a 100644 --- a/aiocraft/mc/auth/mojang.py +++ b/aiocraft/mc/auth/mojang.py @@ -1,23 +1,23 @@ """Minecraft identity utilities.""" import json import uuid -import logging from dataclasses import dataclass from typing import Optional, Dict, Any -import aiohttp from .interface import AuthInterface, AuthException from ..definitions import GameProfile @dataclass class MojangAuthenticator(AuthInterface): + #selectedProfile : GameProfile + #accessToken : str + #session_server_override : str username : str password : Optional[str] - accessToken : str clientToken : str - selectedProfile : GameProfile + auth_server_override : str AGENT_NAME = "Minecraft" AGENT_VERSION = 1 @@ -25,12 +25,19 @@ class MojangAuthenticator(AuthInterface): CONTENT_TYPE = "application/json" HEADERS = {"content-type": CONTENT_TYPE} - def __init__(self, username:str="", password:Optional[str]=None): + def __init__( + self, username:str="", + password:Optional[str]=None, + session_server_override:Optional[str]=None, + auth_server_override:Optional[str]=None, + ): self.username = username self.password = password self.accessToken = "" self.clientToken = "" self.selectedProfile = GameProfile("", username) + self.session_server_override = session_server_override + self.auth_server_override = auth_server_override def __equals__(self, other) -> bool: if not isinstance(other, self.__class__): @@ -48,6 +55,10 @@ class MojangAuthenticator(AuthInterface): def __str__(self) -> str: return repr(self) + @property + def auth_server(self) -> str: + return self.auth_server_override or self.AUTH_SERVER + def serialize(self) -> Dict[str, Any]: return { "username":self.username, @@ -75,7 +86,7 @@ class MojangAuthenticator(AuthInterface): payload["clientToken"] = uuid.uuid4().hex # don't include this to invalidate all other sessions - res = await self._post(self.AUTH_SERVER + "/authenticate", json=payload) + res = await self._post(self.auth_server + "/authenticate", json=payload) self.accessToken=res["accessToken"] self.clientToken=res["clientToken"] @@ -83,11 +94,10 @@ class MojangAuthenticator(AuthInterface): return self - @classmethod - async def sign_out(cls, username:str, password:str) -> dict: - return await cls._post( - cls.AUTH_SERVER + "/signout", - headers=cls.HEADERS, + async def sign_out(self, username:str, password:str) -> dict: + return await self._post( + self.auth_server + "/signout", + headers=self.HEADERS, json={ "username": username, "password": password @@ -98,7 +108,7 @@ class MojangAuthenticator(AuthInterface): if not self.accessToken or not self.clientToken: raise AuthException("/refresh", 0, {"message":"No access token or client token"}, {}) res = await self._post( - self.AUTH_SERVER + "/refresh", + self.auth_server + "/refresh", headers=self.HEADERS, json={ "accessToken": self.accessToken, @@ -122,7 +132,7 @@ class MojangAuthenticator(AuthInterface): if clientToken: payload["clientToken"] = self.clientToken await self._post( - self.AUTH_SERVER + "/validate", + self.auth_server + "/validate", headers=self.HEADERS, json=payload, ) @@ -130,7 +140,7 @@ class MojangAuthenticator(AuthInterface): async def invalidate(self) -> AuthInterface: await self._post( - self.AUTH_SERVER + "/invalidate", + self.auth_server + "/invalidate", headers=self.HEADERS, json= { "accessToken": self.accessToken,