From e4cfee57f895ec65b567ab82cb5e10e40497d66d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Sat, 26 Feb 2011 17:10:22 -0600 Subject: [PATCH] Tunneling account data out to the session to allow for optimizations --- src/alarm_notify.py | 4 +-- src/backends/gv_backend.py | 11 ++----- src/backends/gvoice/gvoice.py | 70 +++++++++++++---------------------------- src/session.py | 20 ++++++------ 4 files changed, 36 insertions(+), 69 deletions(-) diff --git a/src/alarm_notify.py b/src/alarm_notify.py index 5810710..9f7e690 100755 --- a/src/alarm_notify.py +++ b/src/alarm_notify.py @@ -92,7 +92,7 @@ def create_backend(config): loggedIn = False if not loggedIn: - loggedIn = backend.is_authed() + loggedIn = backend.refresh_account_info() is not None if not loggedIn: import base64 @@ -106,7 +106,7 @@ def create_backend(config): for blob in blobs ) username, password = tuple(creds) - loggedIn = backend.login(username, password) + loggedIn = backend.login(username, password) is not None except ConfigParser.NoOptionError, e: pass except ConfigParser.NoSectionError, e: diff --git a/src/backends/gv_backend.py b/src/backends/gv_backend.py index cf7fd6a..f2a3ec2 100644 --- a/src/backends/gv_backend.py +++ b/src/backends/gv_backend.py @@ -45,17 +45,12 @@ class GVDialer(object): def is_quick_login_possible(self): """ - @returns True then is_authed might be enough to login, else full login is required + @returns True then refresh_account_info might be enough to login, else full login is required """ return self._gvoice.is_quick_login_possible() - def is_authed(self, force = False): - """ - Attempts to detect a current session - @note Once logged in try not to reauth more than once a minute. - @returns If authenticated - """ - return self._gvoice.is_authed(force) + def refresh_account_info(self): + return self._gvoice.refresh_account_info() def login(self, username, password): """ diff --git a/src/backends/gvoice/gvoice.py b/src/backends/gvoice/gvoice.py index 3cfd53f..021a03c 100755 --- a/src/backends/gvoice/gvoice.py +++ b/src/backends/gvoice/gvoice.py @@ -170,7 +170,6 @@ class GVoiceBackend(object): SECURE_URL_BASE = "https://www.google.com/voice/" SECURE_MOBILE_URL_BASE = SECURE_URL_BASE + "mobile/" - self._forwardURL = SECURE_MOBILE_URL_BASE + "phones" self._tokenURL = SECURE_URL_BASE + "m" self._callUrl = SECURE_URL_BASE + "call/connect" self._callCancelURL = SECURE_URL_BASE + "call/cancel" @@ -211,9 +210,6 @@ class GVoiceBackend(object): self._XML_MISSED_URL = SECURE_URL_BASE + "inbox/recent/missed/" self._galxRe = re.compile(r"""""", re.MULTILINE | re.DOTALL) - self._tokenRe = re.compile(r"""""") - self._accountNumRe = re.compile(r"""(.{14})""") - self._callbackRe = re.compile(r"""\s+(.*?):\s*(.*?)\s*$""", re.M) self._seperateVoicemailsRegex = re.compile(r"""^\s*
""", re.MULTILINE | re.DOTALL) self._exactVoicemailTimeRegex = re.compile(r"""(.*?)""", re.MULTILINE) @@ -230,32 +226,21 @@ class GVoiceBackend(object): def is_quick_login_possible(self): """ - @returns True then is_authed might be enough to login, else full login is required + @returns True then refresh_account_info might be enough to login, else full login is required """ return self._loadedFromCookies or 0.0 < self._lastAuthed - def is_authed(self, force = False): - """ - Attempts to detect a current session - @note Once logged in try not to reauth more than once a minute. - @returns If authenticated - @blocks - """ - isRecentledAuthed = (time.time() - self._lastAuthed) < 120 - isPreviouslyAuthed = self._token is not None - if isRecentledAuthed and isPreviouslyAuthed and not force: - return True - + def refresh_account_info(self): try: - page = self._get_page(self._forwardURL) - self._grab_account_info(page) + page = self._get_page(self._JSON_CONTACTS_URL) + accountData = self._grab_account_info(page) except Exception, e: _moduleLogger.exception(str(e)) - return False + return None self._browser.save_cookies() self._lastAuthed = time.time() - return True + return accountData def _get_token(self): tokenPage = self._get_page(self._tokenURL) @@ -277,7 +262,7 @@ class GVoiceBackend(object): "btmpl": "mobile", "PersistentCookie": "yes", "GALX": token, - "continue": self._forwardURL, + "continue": self._JSON_CONTACTS_URL, } loginSuccessOrFailurePage = self._get_page(self._loginURL, loginData) @@ -294,19 +279,19 @@ class GVoiceBackend(object): loginSuccessOrFailurePage = self._login(username, password, galxToken) try: - self._grab_account_info(loginSuccessOrFailurePage) + accountData = self._grab_account_info(loginSuccessOrFailurePage) except Exception, e: # Retry in case the redirect failed - # luckily is_authed does everything we need for a retry - loggedIn = self.is_authed(True) - if not loggedIn: + # luckily refresh_account_info does everything we need for a retry + accountData = self.refresh_account_info() + if accountData is None: _moduleLogger.exception(str(e)) - return False + return None _moduleLogger.info("Redirection failed on initial login attempt, auto-corrected for this") self._browser.save_cookies() self._lastAuthed = time.time() - return True + return accountData def persist(self): self._browser.save_cookies() @@ -578,30 +563,18 @@ class GVoiceBackend(object): return flatHtml def _grab_account_info(self, page): - tokenGroup = self._tokenRe.search(page) - if tokenGroup is None: - raise RuntimeError("Could not extract authentication token from GoogleVoice") - self._token = tokenGroup.group(1) - - anGroup = self._accountNumRe.search(page) - if anGroup is not None: - self._accountNum = anGroup.group(1) - else: - _moduleLogger.debug("Could not extract account number from GoogleVoice") - - self._callbackNumbers = {} - for match in self._callbackRe.finditer(page): - callbackNumber = match.group(2) - callbackName = match.group(1) - self._callbackNumbers[callbackNumber] = callbackName + accountData = parse_json(page) + self._token = accountData["r"] + self._accountNum = accountData["number"]["raw"] + for callback in accountData["phones"].itervalues(): + self._callbackNumbers[callback["phoneNumber"]] = callback["name"] if len(self._callbackNumbers) == 0: _moduleLogger.debug("Could not extract callback numbers from GoogleVoice (the troublesome page follows):\n%s" % page) + return accountData def _send_validation(self, number): if not self.is_valid_syntax(number): raise ValueError('Number is not valid: "%s"' % number) - elif not self.is_authed(): - raise RuntimeError("Not Authenticated") return number def _parse_recent(self, recentPages): @@ -986,7 +959,6 @@ def grab_debug_info(username, password): browser = backend._browser _TEST_WEBPAGES = [ - ("forward", backend._forwardURL), ("token", backend._tokenURL), ("login", backend._loginURL), ("isdnd", backend._isDndURL), @@ -1029,8 +1001,8 @@ def grab_debug_info(username, password): backend._grab_account_info(loginSuccessOrFailurePage) except Exception: # Retry in case the redirect failed - # luckily is_authed does everything we need for a retry - loggedIn = backend.is_authed(True) + # luckily refresh_account_info does everything we need for a retry + loggedIn = backend.refresh_account_info() is not None if not loggedIn: raise diff --git a/src/session.py b/src/session.py index 8728b68..bd7914d 100644 --- a/src/session.py +++ b/src/session.py @@ -395,15 +395,15 @@ class Session(QtCore.QObject): self._loggedInTime = self._LOGGINGIN_TIME self.stateChange.emit(self.LOGGINGIN_STATE) finalState = self.LOGGEDOUT_STATE - isLoggedIn = False + accountData = None try: - if not isLoggedIn and self._backend[0].is_quick_login_possible(): - isLoggedIn = yield ( - self._backend[0].is_authed, + if accountData is None and self._backend[0].is_quick_login_possible(): + accountData = yield ( + self._backend[0].refresh_account_info, (), {}, ) - if isLoggedIn: + if accountData is not None: _moduleLogger.info("Logged in through cookies") else: # Force a clearing of the cookies @@ -413,16 +413,16 @@ class Session(QtCore.QObject): {}, ) - if not isLoggedIn: - isLoggedIn = yield ( + if accountData is None: + accountData = yield ( self._backend[0].login, (username, password), {}, ) - if isLoggedIn: + if accountData is not None: _moduleLogger.info("Logged in through credentials") - if isLoggedIn: + if accountData is not None: self._loggedInTime = int(time.time()) oldUsername = self._username self._username = username @@ -454,7 +454,7 @@ class Session(QtCore.QObject): finally: if finalState is not None: self.stateChange.emit(finalState) - if isLoggedIn and self._callback: + if accountData is not None and self._callback: self.set_callback_number(self._callback) def _load(self): -- 1.7.9.5