implemented authentication tokens
This commit is contained in:
parent
13254e61ae
commit
d91840efc9
1 changed files with 101 additions and 0 deletions
101
aiocraft/mc/identity.py
Normal file
101
aiocraft/mc/identity.py
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
"""Minecraft identity utilities."""
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Profile:
|
||||||
|
id : str
|
||||||
|
name : str
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"id": self.id,
|
||||||
|
"name": self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Token:
|
||||||
|
username : str
|
||||||
|
access_token : str
|
||||||
|
client_token : str
|
||||||
|
profile : Profile
|
||||||
|
|
||||||
|
AGENT_NAME = "Minecraft"
|
||||||
|
AGENT_VERSION = 1
|
||||||
|
AUTH_SERVER = "https://authserver.mojang.com"
|
||||||
|
SESSION_SERVER = "https://sessionserver.mojang.com/session/minecraft"
|
||||||
|
CONTENT_TYPE = "application/json"
|
||||||
|
HEADERS = {"content-type": CONTENT_TYPE}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def authenticate(cls, username, password, invalidate=False):
|
||||||
|
payload = {
|
||||||
|
"agent": {
|
||||||
|
"name": cls.AGENT_NAME,
|
||||||
|
"version": cls.AGENT_VERSION
|
||||||
|
},
|
||||||
|
"username": username,
|
||||||
|
"password": password
|
||||||
|
}
|
||||||
|
|
||||||
|
if not invalidate:
|
||||||
|
payload["clientToken"] = uuid.uuid4().hex
|
||||||
|
|
||||||
|
res = await cls._post(cls.AUTH_SERVER + "/authenticate", payload)
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
username=username,
|
||||||
|
access_token=res["accessToken"],
|
||||||
|
client_token=res["clientToken"],
|
||||||
|
profile=Profile(res["selectedProfile"]["id"], res["selectedProfile"]["name"])
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def sign_out(cls, username:str, password:str) -> dict:
|
||||||
|
return await cls._post(cls.AUTH_SERVER + "/signout", {
|
||||||
|
"username": username,
|
||||||
|
"password": password
|
||||||
|
})
|
||||||
|
|
||||||
|
async def refresh(self) -> dict:
|
||||||
|
res = await self._post(self.AUTH_SERVER + "/refresh", {
|
||||||
|
"accessToken": self.access_token,
|
||||||
|
"clientToken": self.client_token
|
||||||
|
})
|
||||||
|
|
||||||
|
self.access_token = res["accessToken"]
|
||||||
|
self.client_token = res["clientToken"]
|
||||||
|
self.profile = Profile(res["selectedProfile"]["id"], res["selectedProfile"]["name"])
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
async def validate(self) -> dict:
|
||||||
|
return await self._post(self.AUTH_SERVER + "/validate", {
|
||||||
|
"accessToken": self.access_token
|
||||||
|
})
|
||||||
|
|
||||||
|
async def invalidate(self) -> dict:
|
||||||
|
return await self._post(self.AUTH_SERVER + "/invalidate", {
|
||||||
|
"accessToken": self.access_token,
|
||||||
|
"clientToken": self.client_token
|
||||||
|
})
|
||||||
|
|
||||||
|
async def join(self, server_id) -> dict:
|
||||||
|
return await self._post(self.SESSION_SERVER + "/join", {
|
||||||
|
"serverId": server_id,
|
||||||
|
"accessToken": self.access_token,
|
||||||
|
"selectedProfile": self.profile.dict()
|
||||||
|
})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
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)
|
||||||
|
|
Loading…
Reference in a new issue