separated auth storage from sys storage

This commit is contained in:
əlemi 2022-04-20 00:02:24 +02:00
parent 6a39e61e03
commit eefa1bf211
No known key found for this signature in database
GPG key ID: BBCBFE5D7244634E
2 changed files with 55 additions and 14 deletions

View file

@ -3,18 +3,28 @@ import json
import sqlite3
from dataclasses import dataclass
from typing import Optional, Any
from typing import Optional, Any, Dict
from datetime import datetime
__DATE_FORMAT__ : str = "%Y-%m-%d %H:%M:%S.%f"
@dataclass
class SystemState:
name : str
token : str
version : str
start_time : int
@dataclass
class AuthenticatorState:
date : datetime
token : Dict[str, Any]
legacy : bool = False
class Storage:
name : str
db : sqlite3.Connection
def __init__(self, name:str):
self.name = name
init = not os.path.isfile(f"{name}.session")
@ -30,14 +40,21 @@ class Storage:
def _init_db(self):
cur = self.db.cursor()
cur.execute('CREATE TABLE system (name TEXT, token TEXT, start_time LONG)')
cur.execute('CREATE TABLE documents (name TEXT, value TEXT)')
cur.execute('CREATE TABLE system (name TEXT PRIMARY KEY, version TEXT, start_time LONG)')
cur.execute('CREATE TABLE documents (name TEXT PRIMARY KEY, value TEXT)')
cur.execute('CREATE TABLE authenticator (date TEXT PRIMARY KEY, token TEXT, legacy BOOL')
self.db.commit()
def _set_state(self, state:SystemState):
cur = self.db.cursor()
cur.execute('DELETE FROM system')
cur.execute('INSERT INTO system VALUES (?, ?, ?)', (state.name, state.token, state.start_time))
cur.execute('INSERT INTO system VALUES (?, ?, ?)', (state.name, state.version, int(state.start_time)))
self.db.commit()
def _set_auth(self, state:AuthenticatorState):
cur = self.db.cursor()
cur.execute('DELETE FROM authenticator')
cur.execute('INSERT INTO authenticator VALUES (?, ?, ?)', (state.date.strftime(__DATE_FORMAT__), json.dumps(state.token), state.legacy))
self.db.commit()
def system(self) -> Optional[SystemState]:
@ -47,10 +64,21 @@ class Storage:
return None
return SystemState(
name=val[0][0],
token=val[0][1],
version=val[0][1],
start_time=val[0][2]
)
def auth(self) -> Optional[AuthenticatorState]:
cur = self.db.cursor()
val = cur.execute('SELECT * FROM authenticator').fetchall()
if not val:
return None
return AuthenticatorState(
date=datetime.strptime(val[0][0], __DATE_FORMAT__),
token=json.loads(val[0][1]),
legacy=val[0][2] or False
)
def get(self, key:str) -> Optional[Any]:
cur = self.db.cursor()
val = cur.execute("SELECT * FROM documents WHERE name = ?", (key,)).fetchall()

View file

@ -4,6 +4,7 @@ import logging
import asyncio
import datetime
import uuid
import pkg_resources
from typing import List, Dict, Optional, Any, Type, get_args, get_origin, get_type_hints, Set, Callable
from time import time
@ -15,9 +16,11 @@ from apscheduler.schedulers.asyncio import AsyncIOScheduler
from aiocraft.mc.packet import Packet
from aiocraft.mc.auth import AuthInterface, AuthException, MojangAuthenticator, MicrosoftAuthenticator, OfflineAuthenticator
from .storage import Storage, SystemState
from .storage import Storage, SystemState, AuthenticatorState
from .game import GameState, GameChat, GameInventory, GameTablist, GameWorld
__VERSION__ = pkg_resources.get_distribution('treepuncher').version
def parse_with_hint(val:str, hint:Any) -> Any:
if hint is bool:
if val.lower() in ['1', 'true', 't', 'on', 'enabled']:
@ -181,11 +184,20 @@ class Treepuncher(
super().__init__(opt('server', required=True), online_mode=online_mode, authenticator=authenticator)
prev = self.storage.system() # if this isn't 1st time, this won't be None. Load token from there
state = SystemState(self.name, __VERSION__, 0)
if prev:
state.start_time = prev.start_time
if self.name != prev.name:
self.logger.warning("Saved session belong to another user")
authenticator.deserialize(json.loads(prev.token))
self.logger.info("Loaded authenticated session")
if prev.version != state.version:
self.logger.warning("Saved session uses a different version")
prev_auth = self.storage.auth()
if prev_auth:
if prev_auth.legacy ^ isinstance(authenticator, MicrosoftAuthenticator):
self.logger.warning("Saved session is incompatible with configured authenticator")
authenticator.deserialize(prev_auth.token)
self.logger.info("Loaded session from %s", prev_auth.date)
self.storage._set_state(state)
@property
@ -194,12 +206,12 @@ class Treepuncher(
async def authenticate(self):
await super().authenticate()
state = SystemState(
name=self.name,
token=json.dumps(self.authenticator.serialize()),
start_time=int(time())
state = AuthenticatorState(
date=datetime.datetime.now(),
token=self.authenticator.serialize(),
legacy=isinstance(self.authenticator, MojangAuthenticator)
)
self.storage._set_state(state)
self.storage._set_auth(state)
async def start(self):
# if self.started: # TODO readd check
@ -213,6 +225,7 @@ class Treepuncher(
self._worker = asyncio.get_event_loop().create_task(self._work())
self.scheduler.resume()
self.logger.info("Treepuncher started")
self.storage._set_state(SystemState(self.name, __VERSION__, time()))
async def stop(self, force: bool = False):
self._processing = False