From 255d8704cc210e41cec2c4b4d4982e3f73dd2739 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sun, 30 Dec 2018 03:38:20 +0100 Subject: [PATCH 1/3] Fix typo in local variable --- hangups/auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hangups/auth.py b/hangups/auth.py index af66972e..0f6c1b3b 100644 --- a/hangups/auth.py +++ b/hangups/auth.py @@ -331,9 +331,9 @@ def _get_authorization_code(session, credentials_prompt): input_selector = PHONE_CODE_SELECTOR else: raise GoogleAuthError('Unknown verification code input') - verfification_code = credentials_prompt.get_verification_code() + verification_code = credentials_prompt.get_verification_code() browser.submit_form( - VERIFICATION_FORM_SELECTOR, {input_selector: verfification_code} + VERIFICATION_FORM_SELECTOR, {input_selector: verification_code} ) try: From 3665492f883d994a1aa9f6dbd8959cc7a8002206 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sun, 30 Dec 2018 03:45:06 +0100 Subject: [PATCH 2/3] Add support for captcha images --- hangups/auth.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/hangups/auth.py b/hangups/auth.py index 0f6c1b3b..b70e900f 100644 --- a/hangups/auth.py +++ b/hangups/auth.py @@ -16,6 +16,7 @@ import logging import platform import urllib.parse +import webbrowser import mechanicalsoup import requests @@ -47,6 +48,7 @@ FORM_SELECTOR = '#gaia_loginform' EMAIL_SELECTOR = '#Email' PASSWORD_SELECTOR = '#Passwd' +CAPTCHA_SELECTOR = '#logincaptcha' VERIFICATION_FORM_SELECTOR = '#challenge' TOTP_CHALLENGE_SELECTOR = '[action="/signin/challenge/totp/2"]' PHONE_CHALLENGE_SELECTOR = '[action="/signin/challenge/ipp/4"]' @@ -130,6 +132,27 @@ def get_authorization_code(): print(MANUAL_LOGIN_INSTRUCTIONS) return input('Authorization code: ') + @staticmethod + def get_captcha_text(url): + """Prompt for captcha text. + + Args: + url (str): The captcha image URL. + + Returns: + str: Captcha text. + + This method automatically opens the captcha image URL in a web browser + using the :mod:`webbrowser` module (exceptions are ignored) and then + prompts the user to enter the captcha text. + """ + try: + logger.info('Detected captcha, opening image in browser: %s', url) + webbrowser.open(url) + except Exception as e: + logger.warning('Failed to open captcha image in browser! (%s)', e) + return input('Captcha text: ') + class RefreshTokenCache(object): """File-based cache for refresh token. @@ -319,6 +342,17 @@ def _get_authorization_code(session, credentials_prompt): password = credentials_prompt.get_password() browser.submit_form(FORM_SELECTOR, {PASSWORD_SELECTOR: password}) + if browser.has_selector(CAPTCHA_SELECTOR): + for image in browser._page.soup.select('div.captcha-img img'): + captcha_text = credentials_prompt.get_captcha_text(image.attrs['src']) + browser.submit_form(FORM_SELECTOR, { + CAPTCHA_SELECTOR: captcha_text, + PASSWORD_SELECTOR: password, + }) + break + else: + logger.warning('Detected captcha but failed to extract image!') + if browser.has_selector(TOTP_CHALLENGE_SELECTOR): browser.submit_form(TOTP_CHALLENGE_SELECTOR, {}) elif browser.has_selector(PHONE_CHALLENGE_SELECTOR): From f7fd1893a8ca0c35c1f9e7dac02bfafa75e174ec Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sun, 30 Dec 2018 23:45:20 +0100 Subject: [PATCH 3/3] Fix flake8 warning (E501) In response to the following build failure: https://travis-ci.org/tdryer/hangups/builds/473486378 --- hangups/auth.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hangups/auth.py b/hangups/auth.py index b70e900f..28e16ece 100644 --- a/hangups/auth.py +++ b/hangups/auth.py @@ -344,7 +344,9 @@ def _get_authorization_code(session, credentials_prompt): if browser.has_selector(CAPTCHA_SELECTOR): for image in browser._page.soup.select('div.captcha-img img'): - captcha_text = credentials_prompt.get_captcha_text(image.attrs['src']) + captcha_text = credentials_prompt.get_captcha_text( + image.attrs['src'] + ) browser.submit_form(FORM_SELECTOR, { CAPTCHA_SELECTOR: captcha_text, PASSWORD_SELECTOR: password,