separated auth storage from sys storage
This commit is contained in:
parent
6a39e61e03
commit
eefa1bf211
2 changed files with 55 additions and 14 deletions
|
@ -3,18 +3,28 @@ import json
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
from dataclasses import dataclass
|
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
|
@dataclass
|
||||||
class SystemState:
|
class SystemState:
|
||||||
name : str
|
name : str
|
||||||
token : str
|
version : str
|
||||||
start_time : int
|
start_time : int
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AuthenticatorState:
|
||||||
|
date : datetime
|
||||||
|
token : Dict[str, Any]
|
||||||
|
legacy : bool = False
|
||||||
|
|
||||||
class Storage:
|
class Storage:
|
||||||
name : str
|
name : str
|
||||||
db : sqlite3.Connection
|
db : sqlite3.Connection
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, name:str):
|
def __init__(self, name:str):
|
||||||
self.name = name
|
self.name = name
|
||||||
init = not os.path.isfile(f"{name}.session")
|
init = not os.path.isfile(f"{name}.session")
|
||||||
|
@ -30,14 +40,21 @@ class Storage:
|
||||||
|
|
||||||
def _init_db(self):
|
def _init_db(self):
|
||||||
cur = self.db.cursor()
|
cur = self.db.cursor()
|
||||||
cur.execute('CREATE TABLE system (name TEXT, token TEXT, start_time LONG)')
|
cur.execute('CREATE TABLE system (name TEXT PRIMARY KEY, version TEXT, start_time LONG)')
|
||||||
cur.execute('CREATE TABLE documents (name TEXT, value TEXT)')
|
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()
|
self.db.commit()
|
||||||
|
|
||||||
def _set_state(self, state:SystemState):
|
def _set_state(self, state:SystemState):
|
||||||
cur = self.db.cursor()
|
cur = self.db.cursor()
|
||||||
cur.execute('DELETE FROM system')
|
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()
|
self.db.commit()
|
||||||
|
|
||||||
def system(self) -> Optional[SystemState]:
|
def system(self) -> Optional[SystemState]:
|
||||||
|
@ -47,10 +64,21 @@ class Storage:
|
||||||
return None
|
return None
|
||||||
return SystemState(
|
return SystemState(
|
||||||
name=val[0][0],
|
name=val[0][0],
|
||||||
token=val[0][1],
|
version=val[0][1],
|
||||||
start_time=val[0][2]
|
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]:
|
def get(self, key:str) -> Optional[Any]:
|
||||||
cur = self.db.cursor()
|
cur = self.db.cursor()
|
||||||
val = cur.execute("SELECT * FROM documents WHERE name = ?", (key,)).fetchall()
|
val = cur.execute("SELECT * FROM documents WHERE name = ?", (key,)).fetchall()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import logging
|
||||||
import asyncio
|
import asyncio
|
||||||
import datetime
|
import datetime
|
||||||
import uuid
|
import uuid
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
from typing import List, Dict, Optional, Any, Type, get_args, get_origin, get_type_hints, Set, Callable
|
from typing import List, Dict, Optional, Any, Type, get_args, get_origin, get_type_hints, Set, Callable
|
||||||
from time import time
|
from time import time
|
||||||
|
@ -15,9 +16,11 @@ from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||||
from aiocraft.mc.packet import Packet
|
from aiocraft.mc.packet import Packet
|
||||||
from aiocraft.mc.auth import AuthInterface, AuthException, MojangAuthenticator, MicrosoftAuthenticator, OfflineAuthenticator
|
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
|
from .game import GameState, GameChat, GameInventory, GameTablist, GameWorld
|
||||||
|
|
||||||
|
__VERSION__ = pkg_resources.get_distribution('treepuncher').version
|
||||||
|
|
||||||
def parse_with_hint(val:str, hint:Any) -> Any:
|
def parse_with_hint(val:str, hint:Any) -> Any:
|
||||||
if hint is bool:
|
if hint is bool:
|
||||||
if val.lower() in ['1', 'true', 't', 'on', 'enabled']:
|
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)
|
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
|
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:
|
if prev:
|
||||||
|
state.start_time = prev.start_time
|
||||||
if self.name != prev.name:
|
if self.name != prev.name:
|
||||||
self.logger.warning("Saved session belong to another user")
|
self.logger.warning("Saved session belong to another user")
|
||||||
authenticator.deserialize(json.loads(prev.token))
|
if prev.version != state.version:
|
||||||
self.logger.info("Loaded authenticated session")
|
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
|
@property
|
||||||
|
@ -194,12 +206,12 @@ class Treepuncher(
|
||||||
|
|
||||||
async def authenticate(self):
|
async def authenticate(self):
|
||||||
await super().authenticate()
|
await super().authenticate()
|
||||||
state = SystemState(
|
state = AuthenticatorState(
|
||||||
name=self.name,
|
date=datetime.datetime.now(),
|
||||||
token=json.dumps(self.authenticator.serialize()),
|
token=self.authenticator.serialize(),
|
||||||
start_time=int(time())
|
legacy=isinstance(self.authenticator, MojangAuthenticator)
|
||||||
)
|
)
|
||||||
self.storage._set_state(state)
|
self.storage._set_auth(state)
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
# if self.started: # TODO readd check
|
# if self.started: # TODO readd check
|
||||||
|
@ -213,6 +225,7 @@ class Treepuncher(
|
||||||
self._worker = asyncio.get_event_loop().create_task(self._work())
|
self._worker = asyncio.get_event_loop().create_task(self._work())
|
||||||
self.scheduler.resume()
|
self.scheduler.resume()
|
||||||
self.logger.info("Treepuncher started")
|
self.logger.info("Treepuncher started")
|
||||||
|
self.storage._set_state(SystemState(self.name, __VERSION__, time()))
|
||||||
|
|
||||||
async def stop(self, force: bool = False):
|
async def stop(self, force: bool = False):
|
||||||
self._processing = False
|
self._processing = False
|
||||||
|
|
Loading…
Reference in a new issue