From 53451dfaf680cd657abe501b2f690d0ba5d41136 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Sun, 18 Mar 2018 00:46:53 -0400 Subject: [PATCH] Implement a setting for manual vs server login method --- gui/builtinPreferenceViews/__init__.py | 1 + .../pyfaCrestPreferences.py | 148 ------------------ .../pyfaEsiPreferences.py | 137 ++++++++++++++++ gui/mainFrame.py | 14 +- gui/preferenceView.py | 2 +- service/esi.py | 42 +++-- service/settings.py | 22 +-- 7 files changed, 187 insertions(+), 179 deletions(-) delete mode 100644 gui/builtinPreferenceViews/pyfaCrestPreferences.py create mode 100644 gui/builtinPreferenceViews/pyfaEsiPreferences.py diff --git a/gui/builtinPreferenceViews/__init__.py b/gui/builtinPreferenceViews/__init__.py index ceec31971..32117a9ec 100644 --- a/gui/builtinPreferenceViews/__init__.py +++ b/gui/builtinPreferenceViews/__init__.py @@ -6,5 +6,6 @@ __all__ = [ "pyfaDatabasePreferences", "pyfaLoggingPreferences", "pyfaEnginePreferences", + "pyfaEsiPreferences", "pyfaStatViewPreferences"] diff --git a/gui/builtinPreferenceViews/pyfaCrestPreferences.py b/gui/builtinPreferenceViews/pyfaCrestPreferences.py deleted file mode 100644 index 598019dab..000000000 --- a/gui/builtinPreferenceViews/pyfaCrestPreferences.py +++ /dev/null @@ -1,148 +0,0 @@ -# noinspection PyPackageRequirements -import wx - -from gui.preferenceView import PreferenceView -from gui.bitmap_loader import BitmapLoader - -import gui.mainFrame - -from service.settings import CRESTSettings - -# noinspection PyPackageRequirements -from wx.lib.intctrl import IntCtrl - -from service.esi import Esi - - -class PFCrestPref(PreferenceView): - title = "CREST" - - def populatePanel(self, panel): - - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.settings = CRESTSettings.getInstance() - self.dirtySettings = False - dlgWidth = panel.GetParent().GetParent().ClientSize.width - mainSizer = wx.BoxSizer(wx.VERTICAL) - - self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0) - self.stTitle.Wrap(-1) - self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) - - mainSizer.Add(self.stTitle, 0, wx.ALL, 5) - - self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) - mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) - - self.stInfo = wx.StaticText(panel, wx.ID_ANY, - "Please see the pyfa wiki on GitHub for information regarding these options.", - wx.DefaultPosition, wx.DefaultSize, 0) - self.stInfo.Wrap(dlgWidth - 50) - mainSizer.Add(self.stInfo, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) - - rbSizer = wx.BoxSizer(wx.HORIZONTAL) - self.rbMode = wx.RadioBox(panel, -1, "Mode", wx.DefaultPosition, wx.DefaultSize, - ['Implicit', 'User-supplied details'], 1, wx.RA_SPECIFY_COLS) - self.rbServer = wx.RadioBox(panel, -1, "Server", wx.DefaultPosition, wx.DefaultSize, - ['Tranquility', 'Singularity'], 1, wx.RA_SPECIFY_COLS) - - self.rbMode.SetSelection(self.settings.get('mode')) - self.rbServer.SetSelection(self.settings.get('server')) - - rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5) - rbSizer.Add(self.rbServer, 1, wx.ALL, 5) - - self.rbMode.Bind(wx.EVT_RADIOBOX, self.OnModeChange) - self.rbServer.Bind(wx.EVT_RADIOBOX, self.OnServerChange) - - mainSizer.Add(rbSizer, 1, wx.ALL | wx.EXPAND, 0) - - timeoutSizer = wx.BoxSizer(wx.HORIZONTAL) - - self.stTimout = wx.StaticText(panel, wx.ID_ANY, "Timeout (seconds):", wx.DefaultPosition, wx.DefaultSize, 0) - self.stTimout.Wrap(-1) - - timeoutSizer.Add(self.stTimout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - - self.intTimeout = IntCtrl(panel, max=300000, limited=True, value=self.settings.get('timeout')) - timeoutSizer.Add(self.intTimeout, 0, wx.ALL, 5) - self.intTimeout.Bind(wx.lib.intctrl.EVT_INT, self.OnTimeoutChange) - - mainSizer.Add(timeoutSizer, 0, wx.ALL | wx.EXPAND, 0) - - detailsTitle = wx.StaticText(panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0) - detailsTitle.Wrap(-1) - detailsTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) - - mainSizer.Add(detailsTitle, 0, wx.ALL, 5) - mainSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, - wx.EXPAND, 5) - - fgAddrSizer = wx.FlexGridSizer(2, 2, 0, 0) - fgAddrSizer.AddGrowableCol(1) - fgAddrSizer.SetFlexibleDirection(wx.BOTH) - fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) - - self.stSetID = wx.StaticText(panel, wx.ID_ANY, "Client ID:", wx.DefaultPosition, wx.DefaultSize, 0) - self.stSetID.Wrap(-1) - fgAddrSizer.Add(self.stSetID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - - self.inputClientID = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition, - wx.DefaultSize, 0) - - fgAddrSizer.Add(self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5) - - self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, "Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0) - self.stSetSecret.Wrap(-1) - - fgAddrSizer.Add(self.stSetSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - - self.inputClientSecret = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition, - wx.DefaultSize, 0) - - fgAddrSizer.Add(self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5) - - self.btnApply = wx.Button(panel, wx.ID_ANY, "Save Client Settings", wx.DefaultPosition, wx.DefaultSize, 0) - self.btnApply.Bind(wx.EVT_BUTTON, self.OnBtnApply) - - mainSizer.Add(fgAddrSizer, 0, wx.EXPAND, 5) - mainSizer.Add(self.btnApply, 0, wx.ALIGN_RIGHT, 5) - - self.ToggleProxySettings(self.settings.get('mode')) - - panel.SetSizer(mainSizer) - panel.Layout() - - def OnTimeoutChange(self, event): - self.settings.set('timeout', event.GetEventObject().GetValue()) - - def OnModeChange(self, event): - self.settings.set('mode', event.GetInt()) - self.ToggleProxySettings(self.settings.get('mode')) - - def OnServerChange(self, event): - self.settings.set('server', event.GetInt()) - - def OnBtnApply(self, event): - self.settings.set('clientID', self.inputClientID.GetValue().strip()) - self.settings.set('clientSecret', self.inputClientSecret.GetValue().strip()) - sEsi = Esi.getInstance() - sEsi.delAllCharacters() - - def ToggleProxySettings(self, mode): - if mode: - self.stSetID.Enable() - self.inputClientID.Enable() - self.stSetSecret.Enable() - self.inputClientSecret.Enable() - else: - self.stSetID.Disable() - self.inputClientID.Disable() - self.stSetSecret.Disable() - self.inputClientSecret.Disable() - - def getImage(self): - return BitmapLoader.getBitmap("eve", "gui") - - -PFCrestPref.register() diff --git a/gui/builtinPreferenceViews/pyfaEsiPreferences.py b/gui/builtinPreferenceViews/pyfaEsiPreferences.py new file mode 100644 index 000000000..029003a83 --- /dev/null +++ b/gui/builtinPreferenceViews/pyfaEsiPreferences.py @@ -0,0 +1,137 @@ +# noinspection PyPackageRequirements +import wx + +from gui.preferenceView import PreferenceView +from gui.bitmap_loader import BitmapLoader + +import gui.mainFrame + +from service.settings import EsiSettings + +# noinspection PyPackageRequirements +from wx.lib.intctrl import IntCtrl + +from service.esi import Esi + + +class PFEsiPref(PreferenceView): + title = "EVE SSO" + + def populatePanel(self, panel): + + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.settings = EsiSettings.getInstance() + self.dirtySettings = False + dlgWidth = panel.GetParent().GetParent().ClientSize.width + mainSizer = wx.BoxSizer(wx.VERTICAL) + + self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0) + self.stTitle.Wrap(-1) + self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) + + mainSizer.Add(self.stTitle, 0, wx.ALL, 5) + + self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) + + self.stInfo = wx.StaticText(panel, wx.ID_ANY, + "Please see the pyfa wiki on GitHub for information regarding these options.", + wx.DefaultPosition, wx.DefaultSize, 0) + self.stInfo.Wrap(dlgWidth - 50) + mainSizer.Add(self.stInfo, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) + + rbSizer = wx.BoxSizer(wx.HORIZONTAL) + self.rbMode = wx.RadioBox(panel, -1, "Login Authentication Method", wx.DefaultPosition, wx.DefaultSize, + ['Local Server', 'Manual'], 1, wx.RA_SPECIFY_COLS) + self.rbMode.SetItemToolTip(0, "This options starts a local webserver that the web application will call back to with information about the character login.") + self.rbMode.SetItemToolTip(1, "This option prompts users to copy and paste information from the web application to allow for character login. Use this if having issues with the local server.") + # self.rbServer = wx.RadioBox(panel, -1, "Server", wx.DefaultPosition, wx.DefaultSize, + # ['Tranquility', 'Singularity'], 1, wx.RA_SPECIFY_COLS) + + self.rbMode.SetSelection(self.settings.get('loginMode')) + # self.rbServer.SetSelection(self.settings.get('server')) + + rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5) + # rbSizer.Add(self.rbServer, 1, wx.ALL, 5) + + self.rbMode.Bind(wx.EVT_RADIOBOX, self.OnModeChange) + # self.rbServer.Bind(wx.EVT_RADIOBOX, self.OnServerChange) + + mainSizer.Add(rbSizer, 1, wx.ALL | wx.EXPAND, 0) + + timeoutSizer = wx.BoxSizer(wx.HORIZONTAL) + + # self.stTimout = wx.StaticText(panel, wx.ID_ANY, "Timeout (seconds):", wx.DefaultPosition, wx.DefaultSize, 0) + # self.stTimout.Wrap(-1) + # + # timeoutSizer.Add(self.stTimout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + + # self.intTimeout = IntCtrl(panel, max=300000, limited=True, value=self.settings.get('timeout')) + # timeoutSizer.Add(self.intTimeout, 0, wx.ALL, 5) + # self.intTimeout.Bind(wx.lib.intctrl.EVT_INT, self.OnTimeoutChange) + # + # mainSizer.Add(timeoutSizer, 0, wx.ALL | wx.EXPAND, 0) + + # detailsTitle = wx.StaticText(panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0) + # detailsTitle.Wrap(-1) + # detailsTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) + # + # mainSizer.Add(detailsTitle, 0, wx.ALL, 5) + # mainSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, + # wx.EXPAND, 5) + + # fgAddrSizer = wx.FlexGridSizer(2, 2, 0, 0) + # fgAddrSizer.AddGrowableCol(1) + # fgAddrSizer.SetFlexibleDirection(wx.BOTH) + # fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + # + # self.stSetID = wx.StaticText(panel, wx.ID_ANY, "Client ID:", wx.DefaultPosition, wx.DefaultSize, 0) + # self.stSetID.Wrap(-1) + # fgAddrSizer.Add(self.stSetID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + # + # self.inputClientID = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition, + # wx.DefaultSize, 0) + # + # fgAddrSizer.Add(self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5) + # + # self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, "Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0) + # self.stSetSecret.Wrap(-1) + # + # fgAddrSizer.Add(self.stSetSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + # + # self.inputClientSecret = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition, + # wx.DefaultSize, 0) + # + # fgAddrSizer.Add(self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5) + # + # self.btnApply = wx.Button(panel, wx.ID_ANY, "Save Client Settings", wx.DefaultPosition, wx.DefaultSize, 0) + # self.btnApply.Bind(wx.EVT_BUTTON, self.OnBtnApply) + # + # mainSizer.Add(fgAddrSizer, 0, wx.EXPAND, 5) + # mainSizer.Add(self.btnApply, 0, wx.ALIGN_RIGHT, 5) + + # self.ToggleProxySettings(self.settings.get('loginMode')) + + panel.SetSizer(mainSizer) + panel.Layout() + + def OnTimeoutChange(self, event): + self.settings.set('timeout', event.GetEventObject().GetValue()) + + def OnModeChange(self, event): + self.settings.set('loginMode', event.GetInt()) + + def OnServerChange(self, event): + self.settings.set('server', event.GetInt()) + + def OnBtnApply(self, event): + self.settings.set('clientID', self.inputClientID.GetValue().strip()) + self.settings.set('clientSecret', self.inputClientSecret.GetValue().strip()) + sEsi = Esi.getInstance() + sEsi.delAllCharacters() + + def getImage(self): + return BitmapLoader.getBitmap("eve", "gui") + + +PFEsiPref.register() diff --git a/gui/mainFrame.py b/gui/mainFrame.py index ffa0364b1..c9e5fa09c 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -83,7 +83,7 @@ import threading import webbrowser import wx.adv -from service.esi import Esi +from service.esi import Esi, LoginMethod from gui.esiFittings import EveFittings, ExportToEve, SsoCharacterMgmt disableOverrideEditor = False @@ -241,12 +241,12 @@ class MainFrame(wx.Frame): self.Bind(GE.EVT_SSO_LOGGING_IN, self.ShowSsoLogin) def ShowSsoLogin(self, event): - dlg = SsoLogin(self) - if dlg.ShowModal() == wx.ID_OK: - sEsi = Esi.getInstance() - # todo: verify that this is a correct SSO Info block - sEsi.handleLogin(dlg.ssoInfoCtrl.Value.strip()) - + if getattr(event, "login_mode", LoginMethod.SERVER) == LoginMethod.MANUAL: + dlg = SsoLogin(self) + if dlg.ShowModal() == wx.ID_OK: + sEsi = Esi.getInstance() + # todo: verify that this is a correct SSO Info block + sEsi.handleLogin(dlg.ssoInfoCtrl.Value.strip()) def ShowUpdateBox(self, release, version): dlg = UpdateDialog(self, release, version) diff --git a/gui/preferenceView.py b/gui/preferenceView.py index 42ce5cd05..9ce2e676d 100644 --- a/gui/preferenceView.py +++ b/gui/preferenceView.py @@ -43,7 +43,7 @@ from gui.builtinPreferenceViews import ( # noqa: E402, F401 pyfaGeneralPreferences, pyfaNetworkPreferences, pyfaHTMLExportPreferences, - # pyfaCrestPreferences, + pyfaEsiPreferences, pyfaContextMenuPreferences, pyfaStatViewPreferences, pyfaUpdatePreferences, diff --git a/service/esi.py b/service/esi.py index 3dbd6496c..675a705ee 100644 --- a/service/esi.py +++ b/service/esi.py @@ -17,6 +17,7 @@ from eos.enum import Enum from eos.saveddata.ssocharacter import SsoCharacter import gui.globalEvents as GE from service.server import StoppableHTTPServer, AuthHandler +from service.settings import EsiSettings from .esi_security_proxy import EsiSecurityProxy from esipy import EsiClient, EsiApp @@ -39,6 +40,11 @@ class Servers(Enum): SISI = 1 +class LoginMethod(Enum): + SERVER = 0 + MANUAL = 1 + + class Esi(object): esiapp = None esi_v1 = None @@ -75,6 +81,8 @@ class Esi(object): def __init__(self): Esi.initEsiApp() + self.settings = EsiSettings.getInstance() + AFTER_TOKEN_REFRESH.add_receiver(self.tokenUpdate) # these will be set when needed @@ -119,7 +127,7 @@ class Esi(object): if char is not None and char.esi_client is None: char.esi_client = Esi.genEsiClient() Esi.update_token(char, Esi.get_sso_data(char)) # don't use update_token on security directly, se still need to apply the values here - print(repr(char)) + eos.db.commit() return char @@ -181,17 +189,33 @@ class Esi(object): char.esi_client.security.update_token(tokenResponse) def login(self): - # Switch off how we do things here depending on the mode of authentication - uri = self.startServer() + serverAddr = None + if self.settings.get('loginMode') == LoginMethod.SERVER: + serverAddr = self.startServer() + uri = self.getLoginURI(serverAddr) webbrowser.open(uri) - wx.PostEvent(self.mainFrame, GE.SsoLoggingIn()) + wx.PostEvent(self.mainFrame, GE.SsoLoggingIn(login_mode=self.settings.get('loginMode'))) def stopServer(self): pyfalog.debug("Stopping Server") self.httpd.stop() self.httpd = None - def startServer(self): + def getLoginURI(self, redirect=None): + self.state = str(uuid.uuid4()) + esisecurity = EsiSecurityProxy(sso_url=config.ESI_AUTH_PROXY) + + args = { + 'state': self.state, + 'pyfa_version': config.version, + } + + if redirect is not None: + args['redirect'] = redirect + + return esisecurity.get_auth_uri(**args) + + def startServer(self): # todo: break this out into two functions: starting the server, and getting the URI pyfalog.debug("Starting server") # we need this to ensure that the previous get_request finishes, and then the socket will close @@ -199,20 +223,14 @@ class Esi(object): self.stopServer() time.sleep(1) - self.state = str(uuid.uuid4()) self.httpd = StoppableHTTPServer(('localhost', 0), AuthHandler) port = self.httpd.socket.getsockname()[1] - - esisecurity = EsiSecurityProxy(sso_url=config.ESI_AUTH_PROXY) - - uri = esisecurity.get_auth_uri(state=self.state, redirect='http://localhost:{}'.format(port), pyfa_version=config.version) - self.serverThread = threading.Thread(target=self.httpd.serve, args=(self.handleServerLogin,)) self.serverThread.name = "SsoCallbackServer" self.serverThread.daemon = True self.serverThread.start() - return uri + return 'http://localhost:{}'.format(port) def handleLogin(self, ssoInfo): auth_response = json.loads(base64.b64decode(ssoInfo)) diff --git a/service/settings.py b/service/settings.py index 7517255c5..ae5ce0e11 100644 --- a/service/settings.py +++ b/service/settings.py @@ -352,32 +352,32 @@ class UpdateSettings(object): self.serviceUpdateSettings[type] = value -class CRESTSettings(object): +class EsiSettings(object): _instance = None @classmethod def getInstance(cls): if cls._instance is None: - cls._instance = CRESTSettings() + cls._instance = EsiSettings() return cls._instance def __init__(self): - # mode - # 0 - Implicit authentication - # 1 - User-supplied client details - serviceCRESTDefaultSettings = {"mode": 0, "server": 0, "clientID": "", "clientSecret": "", "timeout": 60} + # LoginMode: + # 0 - Server Start Up + # 1 - User copy and paste data from website to pyfa + defaults = {"loginMode": 0, "clientID": "", "clientSecret": "", "timeout": 60} - self.serviceCRESTSettings = SettingsProvider.getInstance().getSettings( - "pyfaServiceCRESTSettings", - serviceCRESTDefaultSettings + self.settings = SettingsProvider.getInstance().getSettings( + "pyfaServiceEsiSettings", + defaults ) def get(self, type): - return self.serviceCRESTSettings[type] + return self.settings[type] def set(self, type, value): - self.serviceCRESTSettings[type] = value + self.settings[type] = value class StatViewSettings(object):