def _authenticate_IMAP_connection(self, account, conn): """ Overrides the same method in OAuthAuthHandler so that we can choose a token w/ the appropriate scope. """ host, port = account.imap_endpoint try: token = g_token_manager.get_token_for_email(account) conn.oauth2_login(account.email_address, token) except IMAPClient.Error as exc: log.error('Error during IMAP XOAUTH2 login', account_id=account.id, email=account.email_address, host=host, port=port, error=exc) if not _auth_is_invalid(exc): raise # If we got an AUTHENTICATIONFAILED response, force a token refresh # and try again. If IMAP auth still fails, it's likely that IMAP # access is disabled, so propagate that errror. token = g_token_manager.get_token_for_email( account, force_refresh=True) try: conn.oauth2_login(account.email_address, token) except IMAPClient.Error as exc: if not _auth_is_invalid(exc): raise raise ImapSupportDisabledError()
def get_token(self, account, force_refresh=False): if account.provider == 'gmail': return g_token_manager.get_token_for_email( account, force_refresh=force_refresh) else: return default_token_manager.get_token( account, force_refresh=force_refresh)
def get_gmail_raw_contents(message): account = message.namespace.account auth_token = g_token_manager.get_token_for_email(account) # The Gmail API exposes the X-GM-MSGID field but encodes it # in hexadecimal. g_msgid = message.g_msgid if g_msgid is None: raise EmailDeletedException("Couldn't find message on backend server. This is a permanent error.") if isinstance(g_msgid, basestring): g_msgid = int(g_msgid) hex_id = format(g_msgid, 'x') url = 'https://www.googleapis.com/gmail/v1/users/me/messages/{}?format=raw'.format(hex_id, 'x') r = requests.get(url, auth=OAuthRequestsWrapper(auth_token)) if r.status_code != 200: log.error('Got an error when fetching raw email', r.status_code, r.text) if r.status_code in [403, 429]: raise TemporaryEmailFetchException("Temporary usage limit hit. Please try again.") if r.status_code == 404: raise EmailDeletedException("Couldn't find message on backend server. This is a permanent error.") elif r.status_code >= 500 and r.status_code <= 599: raise TemporaryEmailFetchException("Backend server error. Please try again in a few minutes.") data = r.json() raw = str(data['raw']) return base64.urlsafe_b64decode(raw + '=' * (4 - len(raw) % 4))
def get_token(self, account, force_refresh=False): if account.provider == 'gmail': return g_token_manager.get_token_for_email( account, force_refresh=force_refresh) else: return default_token_manager.get_token(account, force_refresh=force_refresh)
def _search(self, search_query, limit): try: token = g_token_manager.get_token_for_email(self.account) except OAuthError: raise SearchBackendException( "This search can't be performed because the account's " "credentials are out of date. Please reauthenticate and try " "again.", 403) ret = requests.get( u'https://www.googleapis.com/gmail/v1/users/me/messages', params={'q': search_query, 'maxResults': limit}, auth=OAuthRequestsWrapper(token)) log.info('Gmail API search request completed', elapsed=ret.elapsed.total_seconds()) if ret.status_code != 200: log.critical('HTTP error making search request', account_id=self.account.id, url=ret.url, response=ret.content) raise SearchBackendException( "Error issuing search request", 503, server_error=ret.content) data = ret.json() if 'messages' not in data: return [] # Note that the Gmail API returns g_msgids in hex format. So for # example the IMAP X-GM-MSGID 1438297078380071706 corresponds to # 13f5db9286538b1a in the API response we have here. return [int(m['id'], 16) for m in data['messages']]
def _authenticate_IMAP_connection(self, account, conn): """ Overrides the same method in OAuthAuthHandler so that we can choose a token w/ the appropriate scope. """ host, port = account.imap_endpoint try: token = g_token_manager.get_token_for_email(account) conn.oauth2_login(account.email_address, token) except IMAPClient.Error as exc: exc = _process_imap_exception(exc) # Raise all imap disabled errors except authentication_failed # error, swhich we handle differently if isinstance(exc, ImapSupportDisabledError) and \ exc.reason != 'authentication_failed': raise exc log.error('Error during IMAP XOAUTH2 login', account_id=account.id, email=account.email_address, host=host, port=port, error=exc) if not isinstance(exc, ImapSupportDisabledError): raise # Unknown IMAPClient error, reraise # If we got an AUTHENTICATIONFAILED response, force a token refresh # and try again. If IMAP auth still fails, it's likely that IMAP # access is disabled, so propagate that errror. token = g_token_manager.get_token_for_email(account, force_refresh=True) try: conn.oauth2_login(account.email_address, token) except IMAPClient.Error as exc: exc = _process_imap_exception(exc) if not isinstance(exc, ImapSupportDisabledError) or \ exc.reason != 'authentication_failed': raise exc else: # Instead of authentication_failed, report imap disabled raise ImapSupportDisabledError('imap_disabled_for_account')
def __init__(self, account): self.account_id = int(account.id) try: with session_scope(self.account_id) as db_session: self.account = db_session.query(Account).get(self.account_id) self.auth_token = g_token_manager.get_token_for_email(self.account) db_session.expunge_all() except OAuthError: raise SearchBackendException( "This search can't be performed because the account's " "credentials are out of date. Please reauthenticate and try " "again.", 403)
def __init__(self, account): self.account_id = int(account.id) try: with session_scope(self.account_id) as db_session: self.account = db_session.query(Account).get(self.account_id) self.auth_token = g_token_manager.get_token_for_email( self.account) db_session.expunge_all() except OAuthError: raise SearchBackendException( "This search can't be performed because the account's " "credentials are out of date. Please reauthenticate and try " "again.", 403)
def _authenticate_IMAP_connection(self, account, conn): """ Overrides the same method in OAuthAuthHandler so that we can choose a token w/ the appropriate scope. """ host, port = account.imap_endpoint try: token = g_token_manager.get_token_for_email(account) conn.oauth2_login(account.email_address, token) except IMAPClient.Error as exc: exc = _process_imap_exception(exc) # Raise all imap disabled errors except authentication_failed # error, swhich we handle differently if isinstance(exc, ImapSupportDisabledError) and \ exc.reason != 'authentication_failed': raise exc log.error('Error during IMAP XOAUTH2 login', account_id=account.id, email=account.email_address, host=host, port=port, error=exc) if not isinstance(exc, ImapSupportDisabledError): raise # Unknown IMAPClient error, reraise # If we got an AUTHENTICATIONFAILED response, force a token refresh # and try again. If IMAP auth still fails, it's likely that IMAP # access is disabled, so propagate that errror. token = g_token_manager.get_token_for_email( account, force_refresh=True) try: conn.oauth2_login(account.email_address, token) except IMAPClient.Error as exc: exc = _process_imap_exception(exc) if not isinstance(exc, ImapSupportDisabledError) or \ exc.reason != 'authentication_failed': raise exc else: # Instead of authentication_failed, report imap disabled raise ImapSupportDisabledError('imap_disabled_for_account')
def _authenticate_IMAP_connection(self, account, conn): """ Overrides the same method in OAuthAuthHandler so that we can choose a token w/ the appropriate scope. """ host, port = account.imap_endpoint try: token = g_token_manager.get_token_for_email(account) conn.oauth2_login(account.email_address, token) except IMAPClient.Error as exc: log.error('Error during IMAP XOAUTH2 login', account_id=account.id, email=account.email_address, host=host, port=port, error=exc) raise
def get_gmail_raw_contents(message): account = message.namespace.account auth_token = g_token_manager.get_token_for_email(account) # The Gmail API exposes the X-GM-MSGID field but encodes it # in hexadecimal. g_msgid = message.g_msgid if g_msgid is None: raise EmailDeletedException( "Couldn't find message on backend server. This is a permanent error." ) if isinstance(g_msgid, basestring): g_msgid = int(g_msgid) hex_id = format(g_msgid, 'x') url = 'https://www.googleapis.com/gmail/v1/users/me/messages/{}?format=raw'.format( hex_id, 'x') r = requests.get(url, auth=OAuthRequestsWrapper(auth_token)) if r.status_code != 200: log.error('Got an error when fetching raw email', r.status_code, r.text) if r.status_code in [403, 429]: raise TemporaryEmailFetchException( "Temporary usage limit hit. Please try again.") if r.status_code == 404: raise EmailDeletedException( "Couldn't find message on backend server. This is a permanent error." ) elif r.status_code >= 500 and r.status_code <= 599: raise TemporaryEmailFetchException( "Backend server error. Please try again in a few minutes.") data = r.json() raw = str(data['raw']) return base64.urlsafe_b64decode(raw + '=' * (4 - len(raw) % 4))