Prechádzať zdrojové kódy

Fix problem with non secure browser

JoostSijm 4 rokov pred
rodič
commit
ebf875063a

+ 23 - 1
README.md

@@ -24,7 +24,7 @@ If you are unsure middleware to use, then it is advised to implement LocalAuthen
 
 LocalAuthentication is used to login in directly into Rival Regions using supported login methods.
 When running into issues with login then I would appreciate if you could help me resolve the issue. 
-Available login methods: google (supported), vk (may work, never tested), facebook (may work, never tested)
+Available login methods: Google (supported), vk (may work, never tested), facebook (may work, never tested)
 Use username, password, and login method to log in local instance of the authenticator.
 
 RemoteAuthentication connects through a remote API using URL and authentication key.
@@ -35,6 +35,28 @@ article, conference, craft, language\_chat, market, overview, perks, profile, re
 For now there is limited documentation how to use the wrapper classes.
 Read the files [here](https://github.com/joostsijm/rival_regions_wrapper/tree/dev/src/rival_regions_wrapper/wrapper) to see how they work.
 
+## Problems
+### This browser or app may not be secure
+Probably the most common problems you may encounter will be about authentication your account.
+In some cases for Google accounts while logging in the browser automation tools are detected.
+After submitting the google username it gets a prompt that says: "This browser or app may not be secure".
+To resolve this problem it is required to run the library with the `show_window` option, when you start the library it will show a Google Chrome window.
+This is required because you will have to fill in your loggin credentials by yourself.
+It is only required once, because from then on your Google authentication is saved in the Chrome profile.
+
+1. To start the library with `show_window` option, add `True` to the initializing of the LocalAuthentication class, like this: `LocalAuthentication(True)`.
+2. Start your application, you will see a Google Chrome window what fills in your username.
+4. After submitting your username you see the error message, and a new tab opens.
+5. In the new tab log into your Google account.
+6. After sucessfully loggin in wait until Google Chrome closes.
+
+From now on you should be able to use your Google account with the library without a problem.
+You can disable the library show\_window option by removing `True` when calling the `LocalAuthentication`.
+
+### Captcha
+When loggin in to your Google account makes you fill out a captcha you can use [anti-captcha](https://anti-captcha.com/) service to circumvent them. 
+Put the key into the LocalAuthenticator after the show\_window option, like this: `LocalAuthentication(False, <ant_captcha_key>)`.
+
 ## Examples
 Create LocalAuthentication middleware and log in using environ variables.
 ```python

+ 12 - 12
src/rival_regions_wrapper/authentication_handler.py

@@ -4,14 +4,14 @@ Authentication handler module
 
 import re
 
-import requests
 import cfscrape
+from python_anticaptcha import AnticaptchaClient
 
-from rival_regions_wrapper import LOGGER, login_methods
+from rival_regions_wrapper import LOGGER, DATA_DIR, login_methods
 from rival_regions_wrapper.cookie_handler import CookieHandler
 from rival_regions_wrapper.browser import Browser
 from rival_regions_wrapper.exceptions import InvalidLoginMethodException, \
-        SessionExpireException, NoLogginException, NoCookieException
+        NoLogginException, NoCookieException
 
 
 LOGIN_METHOD_DICT = {
@@ -26,12 +26,15 @@ LOGIN_METHOD_DICT = {
 
 class AuthenticationHandler:
     """class for RR client"""
-    def __init__(self, show_window=False, captcha_client=None):
-        LOGGER.info('Initialize, show window: "%s", captcha client: "%s"',
-                show_window, bool(captcha_client)
+    def __init__(self, show_window=False, captcha_key=None):
+        LOGGER.info('Initialize, show window: "%s", captcha key: "%s"',
+                show_window, bool(captcha_key)
             )
         self.show_window = show_window
-        self.captcha_client = captcha_client
+        if captcha_key:
+            self.captcha_client = AnticaptchaClient(captcha_key)
+        else:
+            self.captcha_client = None
         self.login_method = None
         self.username = None
         self.password = None
@@ -79,11 +82,8 @@ class AuthenticationHandler:
 
     def login(self):
         """Login"""
-        auth_text = requests.get("https://rivalregions.com").text
-        browser = Browser(showWindow=self.show_window)
         browser = LOGIN_METHOD_DICT[self.login_method](
-                browser,
-                auth_text,
+                self.show_window,
                 self.username,
                 self.password,
                 self.captcha_client
@@ -114,7 +114,7 @@ class AuthenticationHandler:
         if not self.session:
             raise NoLogginException()
 
-        browser = Browser(showWindow=self.show_window)
+        browser = Browser(self.show_window, DATA_DIR, self.username)
         browser.go_to('https://rivalregions.com/')
         for cookie_name, value in \
                 self.session.cookies.get_dict().items():

+ 5 - 43
src/rival_regions_wrapper/browser.py

@@ -2,9 +2,6 @@
 Browser module
 """
 
-import os
-import errno
-
 from selenium_stealth import stealth
 from selenium import webdriver
 from selenium.webdriver.common.keys import Keys
@@ -12,33 +9,9 @@ import webbot
 
 
 class Browser(webbot.Browser):
-    """
-    **Constructor**
-
-
-    :__init__(showWindow = True , proxy = None):
-        The constructor takes showWindow flag as argument which Defaults
-                to False. If it is set to true , all browser happen without
-                showing up any GUI window .
-
-        :Args:
-            - showWindow : If true , will run a headless browser without
-                    showing GUI window.
-            - proxy : Url of any optional proxy server.
-
+    """Browser class"""
+    def __init__(self, show_window=True, data_dir='chrome', username='Profile 1'):
 
-
-    Object attributes:  Key , errors
-
-    :Key:
-        - It contains the constants for all the special keys in the keyboard
-                which can be used in the *press* method
-    errors:
-        - List containing all the errors which might have occurred during
-                performing an action like click ,type etc.
-    """
-    def __init__(self, showWindow=True, proxy=None, downloadPath=None):
-        super().__init__(showWindow, proxy, downloadPath)
         options = webdriver.ChromeOptions()
         options.add_argument("--disable-dev-shm-usage")
         options.add_argument("--no-sandbox")
@@ -50,21 +23,10 @@ class Browser(webbot.Browser):
                 "excludeSwitches", ["enable-automation"]
             )
         options.add_experimental_option('useAutomationExtension', False)
-        if downloadPath is not None and isinstance(downloadPath, str):
-            absolute_path = os.path.abspath(downloadPath)
-            if not os.path.isdir(absolute_path):
-                raise FileNotFoundError(
-                        errno.ENOENT, os.strerror(errno.ENOENT), absolute_path
-                    )
-
-            options.add_experimental_option(
-                    'prefs', {'download.default_directory': absolute_path}
-                )
-
-        if proxy is not None and isinstance(proxy, str):
-            options.add_argument("--proxy-server={}".format(proxy))
+        options.add_argument("--user-data-dir={}/chrome".format(data_dir))
+        options.add_argument("--profile-directory={}".format(username))
 
-        if not showWindow:
+        if not show_window:
             options.headless = True
 
         self.driver = webdriver.Chrome(options=options)

+ 53 - 42
src/rival_regions_wrapper/login_methods.py

@@ -4,35 +4,52 @@ import time
 
 import requests
 from python_anticaptcha import ImageToTextTask
+from selenium.common.exceptions import NoSuchElementException
 
-from rival_regions_wrapper import LOGGER
+from rival_regions_wrapper import LOGGER, DATA_DIR
+from rival_regions_wrapper.browser import Browser
 from rival_regions_wrapper.exceptions import NoCaptchaClientException, \
         LoginException
 
 
 # This should be working
-def login_google(browser, auth_text, username, password, captcha_client=None):
+def login_google(show_window, username, password, captcha_client=None):
     """login using Google"""
+    browser = Browser(show_window, DATA_DIR, 'g_{}'.format(username))
     LOGGER.info('Google: "%s": Login start', username)
-    auth_text1 = auth_text.split('\t<a href="')
-    auth_text2 = auth_text1[1].split('" class="sa')
-    time.sleep(1)
-    browser.go_to(auth_text2[0])
+    try:
+        # browser = Browser(show_window, DATA_DIR, 'g_{}'.format(username))
+        browser.go_to('https://rivalregions.com/')
+        google_login_link = browser.driver.find_element_by_css_selector(
+                '.sa_link.gogo'
+            ).get_attribute('href')
+        browser.go_to(google_login_link)
+        time.sleep(0.5)
+    except NoSuchElementException:
+        LOGGER.info('Google: "%s": still RR session active', username)
+        return browser
 
     # browser.get_screenshot_as_file('test_1.png')
 
+    if browser.driver.find_elements_by_css_selector('#gold'):
+        LOGGER.info('Google: "%s": account already logged in', username)
+        return browser
+
     LOGGER.info('Google: "%s": Typing in username', username)
-    browser.type(username, into='Email')
+    if not browser.driver.find_elements_by_css_selector('#Email'):
+        LOGGER.info('Google: "%s": problem with fill in password', username)
+        raise LoginException() from NoSuchElementException
+    browser.type(username, css_selector='#Email')
 
     # browser.get_screenshot_as_file('test_2.png')
 
     LOGGER.info('Google: "%s": pressing next button', username)
     browser.click(css_selector='#next')
-    time.sleep(1)
+    time.sleep(0.5)
 
     # browser.get_screenshot_as_file('test_3.png')
 
-    if browser.driver.find_elements_by_css_selector('#captcha-box'):
+    while browser.driver.find_elements_by_css_selector('#captcha-box'):
         LOGGER.info('Google: "%s": Captcha present', username)
         if not captcha_client:
             raise NoCaptchaClientException()
@@ -43,21 +60,33 @@ def login_google(browser, auth_text, username, password, captcha_client=None):
         image = requests.get(captcha_url, stream=True).raw
         image.decode_content = True
 
-        task = ImageToTextTask(image)
-        job = captcha_client.createTask(task)
+        job = captcha_client.createTask(ImageToTextTask(image))
         LOGGER.info('Google: "%s": Start solve captcha', username)
         job.join()
-
-        LOGGER.info('Google: %s": captcha: "%s"', username, job.get_captcha_text())
+        LOGGER.info('Google: "%s": captcha: "%s"',
+                username, job.get_captcha_text()
+            )
         browser.type(
                 job.get_captcha_text(),
                 css_selector='#identifier-captcha-input'
             )
         browser.click(css_selector='#next')
+        time.sleep(0.5)
 
         # browser.get_screenshot_as_file('test_4.png')
 
     if not browser.driver.find_elements_by_css_selector('#password'):
+        LOGGER.info('Google: "%s": browser security issue', username)
+        if show_window:
+            browser.new_tab('https://accounts.google.com/')
+            LOGGER.info('Google: "%s": fill in credentials', username)
+            while not browser.driver.find_elements_by_css_selector('#gold'):
+                time.sleep(2)
+                LOGGER.info('Google: "%s": waiting to fill in credentials',
+                        username
+                    )
+                browser.go_to(google_login_link)
+            return browser
         raise LoginException()
 
     # with open('source.html', 'w') as source:
@@ -70,39 +99,22 @@ def login_google(browser, auth_text, username, password, captcha_client=None):
 
     LOGGER.info('Google: "%s": pressing sign in button', username)
     browser.click(css_selector='#submit')
-    time.sleep(3)
+    time.sleep(0.5)
 
     # browser.get_screenshot_as_file('test_6.png')
 
-    # Some why it wont click and login immediately. This seems to work
-    browser.go_to(auth_text2[0])
-    time.sleep(1)
-
-    # browser.get_screenshot_as_file('test_7.png')
-
-    browser.go_to(auth_text2[0])
-    time.sleep(1)
-
-    # browser.get_screenshot_as_file('test_8.png')
-
-    browser.click(
-        css_selector='#sa_add2 > div:nth-child(4) > a.sa_link.gogo > div'
-    )
-    time.sleep(2)
-
-    # browser.get_screenshot_as_file('test_9.png')
-
     return browser
 
 
 # IDK if this is working
-def login_vk(browser, auth_text, username, password, captcha_client=None):
+def login_vk(show_window, username, password, captcha_client=None):
     """login using VK"""
+    browser = Browser(show_window, DATA_DIR, 'vk_{}'.format(username))
     LOGGER.info('Login method VK')
-    auth_text1 = auth_text.split("(\'.vkvk\').attr(\'url\', \'")
-    auth_text2 = auth_text1[1].split('&response')
+    browser.go_to('https://rivalregions.com/')
+    browser.click(css_selector='.sa_sn.imp.float_left')
+    time.sleep(1)
 
-    browser.go_to(auth_text2[0])
     browser.type(username, into='email')
     browser.type(
             password,
@@ -113,15 +125,14 @@ def login_vk(browser, auth_text, username, password, captcha_client=None):
 
 
 # IDK if this is working
-def login_facebook(browser, auth_text, username, password, captcha_client=None):
+def login_facebook(show_window, username, password, captcha_client=None):
     """login using Facebook"""
+    browser = Browser(show_window, DATA_DIR, 'fb_{}'.format(username))
     LOGGER.info('Login method Facebook')
-    auth_text1 = \
-        auth_text.split('">\r\n\t\t\t\t<div class="sa_sn imp float_left" ')
-    auth_text2 = auth_text1[0].split('200px;"><a class="sa_link" href="')
-    url = auth_text2[1]
+    browser.go_to('https://rivalregions.com/')
+    browser.click(css_selector='sa_sn.float_left.imp.vkvk')
+    time.sleep(1)
 
-    browser.go_to(url)
     browser.type(username, into='Email')
     browser.type(password, into='Password')
     browser.click('Log In')