diff --git a/config.py b/config.py index 339a19e0a..1127b72ae 100644 --- a/config.py +++ b/config.py @@ -3,6 +3,7 @@ import sys from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, \ StreamHandler, TimedRotatingFileHandler, WARNING +import hashlib pyfalog = Logger(__name__) @@ -43,6 +44,10 @@ LOGLEVEL_MAP = { } +def getClientSecret(): + return hashlib.sha3_256("This is a secret, this will not remain in here for long".encode('utf-8')).hexdigest() + + def isFrozen(): if hasattr(sys, 'frozen'): return True diff --git a/eos/db/saveddata/crest.py b/eos/db/saveddata/crest.py index 28f77a983..035cdb60d 100644 --- a/eos/db/saveddata/crest.py +++ b/eos/db/saveddata/crest.py @@ -22,13 +22,17 @@ from sqlalchemy.orm import mapper import datetime from eos.db import saveddata_meta -from eos.saveddata.crestchar import CrestChar +from eos.saveddata.ssocharacter import SsoCharacter -crest_table = Table("crest", saveddata_meta, +sso_table = Table("ssoCharacter", saveddata_meta, Column("ID", Integer, primary_key=True), - Column("name", String, nullable=False, unique=True), - Column("refresh_token", String, nullable=False), - # These records aren't updated. Instead, they are dropped and created, hence we don't have a modified field - Column("created", DateTime, nullable=True, default=datetime.datetime.now)) + Column("client", String, nullable=False), + Column("characterID", Integer, nullable=False, unique=True), + Column("characterName", String, nullable=False, unique=True), + Column("refreshToken", String, nullable=False), + Column("accessToken", String, nullable=False), + Column("accessTokenExpires", DateTime, nullable=False), + Column("created", DateTime, nullable=True, default=datetime.datetime.now), + Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now)) -mapper(CrestChar, crest_table) +mapper(SsoCharacter, sso_table) diff --git a/eos/db/saveddata/queries.py b/eos/db/saveddata/queries.py index 98902007f..b3c1840e8 100644 --- a/eos/db/saveddata/queries.py +++ b/eos/db/saveddata/queries.py @@ -27,7 +27,7 @@ from eos.db.saveddata.fit import projectedFits_table from eos.db.util import processEager, processWhere from eos.saveddata.price import Price from eos.saveddata.user import User -from eos.saveddata.crestchar import CrestChar +from eos.saveddata.ssocharacter import SsoCharacter from eos.saveddata.damagePattern import DamagePattern from eos.saveddata.targetResists import TargetResists from eos.saveddata.character import Character @@ -467,27 +467,27 @@ def getProjectedFits(fitID): raise TypeError("Need integer as argument") -def getCrestCharacters(eager=None): +def getSsoCharacters(eager=None): eager = processEager(eager) with sd_lock: - characters = saveddata_session.query(CrestChar).options(*eager).all() + characters = saveddata_session.query(SsoCharacter).options(*eager).all() return characters -@cachedQuery(CrestChar, 1, "lookfor") -def getCrestCharacter(lookfor, eager=None): +@cachedQuery(SsoCharacter, 1, "lookfor") +def getSsoCharacter(lookfor, eager=None): if isinstance(lookfor, int): if eager is None: with sd_lock: - character = saveddata_session.query(CrestChar).get(lookfor) + character = saveddata_session.query(SsoCharacter).get(lookfor) else: eager = processEager(eager) with sd_lock: - character = saveddata_session.query(CrestChar).options(*eager).filter(CrestChar.ID == lookfor).first() + character = saveddata_session.query(SsoCharacter).options(*eager).filter(SsoCharacter.ID == lookfor).first() elif isinstance(lookfor, str): eager = processEager(eager) with sd_lock: - character = saveddata_session.query(CrestChar).options(*eager).filter(CrestChar.name == lookfor).first() + character = saveddata_session.query(SsoCharacter).options(*eager).filter(SsoCharacter.name == lookfor).first() else: raise TypeError("Need integer or string as argument") return character diff --git a/eos/saveddata/crestchar.py b/eos/saveddata/crestchar.py deleted file mode 100644 index ce6ab14fe..000000000 --- a/eos/saveddata/crestchar.py +++ /dev/null @@ -1,34 +0,0 @@ -# =============================================================================== -# Copyright (C) 2010 Diego Duclos -# -# This file is part of eos. -# -# eos is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# eos is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with eos. If not, see . -# =============================================================================== - -from sqlalchemy.orm import reconstructor - - -# from tomorrow import threads - - -class CrestChar(object): - def __init__(self, id, name, refresh_token=None): - self.ID = id - self.name = name - self.refresh_token = refresh_token - - @reconstructor - def init(self): - pass diff --git a/eos/saveddata/ssocharacter.py b/eos/saveddata/ssocharacter.py new file mode 100644 index 000000000..8fca830cb --- /dev/null +++ b/eos/saveddata/ssocharacter.py @@ -0,0 +1,60 @@ +# =============================================================================== +# Copyright (C) 2010 Diego Duclos +# +# This file is part of eos. +# +# eos is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# eos is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with eos. If not, see . +# =============================================================================== + +from sqlalchemy.orm import reconstructor +import datetime +import time + +# from tomorrow import threads + + +class SsoCharacter(object): + def __init__(self, id, charID, name, client, accessToken, refreshToken=None): + self.ID = id + self.characterID = charID + self.characterName = name + self.client = client + self.accessToken = accessToken + self.refreshToken = refreshToken + + @reconstructor + def init(self): + pass + + def get_sso_data(self): + """ Little "helper" function to get formated data for esipy security + """ + return { + 'access_token': self.accessToken, + 'refresh_token': self.refreshToken, + 'expires_in': ( + self.accessTokenExpires - datetime.utcnow() + ).total_seconds() + } + + def update_token(self, tokenResponse): + """ helper function to update token data from SSO response """ + self.accessToken = tokenResponse['access_token'] + self.accessTokenExpires = datetime.fromtimestamp( + time.time() + tokenResponse['expires_in'], + ) + if 'refresh_token' in tokenResponse: + self.refreshToken = tokenResponse['refresh_token'] + if self.esi_client is not None: + self.esi_client.security.update_token(tokenResponse) \ No newline at end of file diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 2aa6bb750..735db0d80 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -662,16 +662,8 @@ class MainFrame(wx.Frame): menu.Enable(menu.exportToEveId, not enable) def ssoHandler(self, event): - sCrest = Crest.getInstance() - if sCrest.settings.get('mode') == CrestModes.IMPLICIT: - if sCrest.implicitCharacter is not None: - sCrest.logout() - else: - uri = sCrest.startServer() - webbrowser.open(uri) - else: - dlg = CrestMgmt(self) - dlg.Show() + dlg = CrestMgmt(self) + dlg.Show() def exportToEve(self, event): dlg = ExportToEve(self) diff --git a/gui/mainMenuBar.py b/gui/mainMenuBar.py index be9322010..8b5b77e60 100644 --- a/gui/mainMenuBar.py +++ b/gui/mainMenuBar.py @@ -28,8 +28,8 @@ import gui.globalEvents as GE from gui.bitmap_loader import BitmapLoader from logbook import Logger -from service.crest import Crest -from service.crest import CrestModes +# from service.crest import Crest +# from service.crest import CrestModes pyfalog = Logger(__name__) @@ -134,21 +134,19 @@ class MainMenuBar(wx.MenuBar): preferencesItem.SetBitmap(BitmapLoader.getBitmap("preferences_small", "gui")) windowMenu.Append(preferencesItem) - self.sCrest = Crest.getInstance() + # self.sCrest = Crest.getInstance() # CREST Menu crestMenu = wx.Menu() self.Append(crestMenu, "&CREST") - if self.sCrest.settings.get('mode') != CrestModes.IMPLICIT: - crestMenu.Append(self.ssoLoginId, "Manage Characters") - else: - crestMenu.Append(self.ssoLoginId, "Login to EVE") + + crestMenu.Append(self.ssoLoginId, "Manage Characters") crestMenu.Append(self.eveFittingsId, "Browse EVE Fittings") crestMenu.Append(self.exportToEveId, "Export To EVE") - if self.sCrest.settings.get('mode') == CrestModes.IMPLICIT or len(self.sCrest.getCrestCharacters()) == 0: - self.Enable(self.eveFittingsId, False) - self.Enable(self.exportToEveId, False) + # if self.sCrest.settings.get('mode') == CrestModes.IMPLICIT or len(self.sCrest.getCrestCharacters()) == 0: + self.Enable(self.eveFittingsId, False) + self.Enable(self.exportToEveId, False) if not self.mainFrame.disableOverrideEditor: windowMenu.AppendSeparator() diff --git a/service/crest.py b/service/crest.py index ff1765298..51c9f1309 100644 --- a/service/crest.py +++ b/service/crest.py @@ -8,7 +8,7 @@ import time import eos.db from eos.enum import Enum -from eos.saveddata.crestchar import CrestChar +from eos.saveddata.ssocharacter import SsoCharacter import gui.globalEvents as GE from service.settings import CRESTSettings from service.server import StoppableHTTPServer, AuthHandler @@ -100,40 +100,30 @@ class Crest(object): return self.settings.get('server') == Servers.SISI def delCrestCharacter(self, charID): - char = eos.db.getCrestCharacter(charID) + char = eos.db.getSsoCharacter(charID) del self.charCache[char.ID] eos.db.remove(char) wx.PostEvent(self.mainFrame, GE.SsoLogout(type=CrestModes.USER, numChars=len(self.charCache))) def delAllCharacters(self): - chars = eos.db.getCrestCharacters() + chars = eos.db.getSsoCharacters() for char in chars: eos.db.remove(char) self.charCache = {} wx.PostEvent(self.mainFrame, GE.SsoLogout(type=CrestModes.USER, numChars=0)) def getCrestCharacters(self): - chars = eos.db.getCrestCharacters() - # I really need to figure out that DB cache problem, this is ridiculous - chars2 = [self.getCrestCharacter(char.ID) for char in chars] - return chars2 + chars = eos.db.getSsoCharacters() + return chars def getCrestCharacter(self, charID): """ Get character, and modify to include the eve connection """ - if self.settings.get('mode') == CrestModes.IMPLICIT: - if self.implicitCharacter.ID != charID: - raise ValueError("CharacterID does not match currently logged in character.") - return self.implicitCharacter - if charID in self.charCache: return self.charCache.get(charID) - char = eos.db.getCrestCharacter(charID) - if char and not hasattr(char, "eve"): - char.eve = EVE(**self.eve_options) - char.eve.temptoken_authorize(refresh_token=char.refresh_token) + char = eos.db.getSsoCharacter(charID) self.charCache[charID] = char return char diff --git a/service/esi.py b/service/esi.py index 0125c42c4..0f375a591 100644 --- a/service/esi.py +++ b/service/esi.py @@ -8,7 +8,7 @@ import time import eos.db from eos.enum import Enum -from eos.saveddata.crestchar import CrestChar +from eos.saveddata.ssocharacter import CrestChar import gui.globalEvents as GE from service.settings import CRESTSettings from service.server import StoppableHTTPServer, AuthHandler