Advertisement
stuppid_bot

Untitled

Jan 19th, 2016
256
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.61 KB | None | 0 0
  1. from .access_token import AccessToken
  2. import logging
  3. import re
  4. import urllib.parse
  5.  
  6.  
  7. AUTH_BASE = "https://oauth.vk.com"
  8. REDIRECT_URI = AUTH_BASE + "/blank.html"
  9.  
  10.  
  11. class AuthMixin:
  12.     def get_auth_url(self, params):
  13.         return "{}?{}".format(
  14.             urllib.parse.urljoin(AUTH_BASE, self.auth_path),
  15.             urllib.parse.urlencode(params)
  16.         )
  17.  
  18.  
  19. class DirectAuth(AuthMixin):
  20.     """Осуществляет прямую авторизацию <https://vk.com/dev/auth_direct>"""
  21.     auth_path = 'token'
  22.  
  23.     def __init__(self,
  24.                  client,
  25.                  client_id,
  26.                  client_secret,
  27.                  scope=None,
  28.                  username=None,
  29.                  password=None,
  30.                  test_redirect_uri=None):
  31.         self.logger = logging.getLogger(
  32.             ".".join([self.__class__.__module__, self.__class__.__name__]))
  33.         self.client = client
  34.         self.client_id = client_id
  35.         self.client_secret = client_secret
  36.         self.scope = scope
  37.         self.username = username
  38.         self.password = password
  39.         self.test_redirect_uri = test_redirect_uri
  40.  
  41.     def authorize(self,
  42.                   username=None,
  43.                   password=None,
  44.                   captcha_key=None,
  45.                   captcha_sid=None):
  46.         self.username = username or self.username
  47.         self.password = password or self.password
  48.         if not self.username or not self.password:
  49.             raise AuthError("Username and password are required")
  50.         params = self.get_params()
  51.         if captcha_key:
  52.             params['captcha_key'] = captcha_key
  53.             params['captcha_sid'] = captcha_sid
  54.         url = self.get_auth_url(params)
  55.         self.logger.debug("Url: %s", url)
  56.         response = self.client.get(url)
  57.         self.process_response(response)
  58.  
  59.     def get_params(self):
  60.         params = dict(
  61.             grant_type='password',
  62.             client_id=self.client_id,
  63.             client_secret=self.client_secret,
  64.             username=self.username,
  65.             password=self.password,
  66.             v=self.client.api_version
  67.         )
  68.         if self.scope:
  69.             params['scope'] = self.scope
  70.         if self.test_redirect_uri:
  71.             params['test_redirect_uri']
  72.         return params
  73.  
  74.     def process_response(self, response):
  75.         """
  76.        Обработку ошибок можно реализовать в классе наследнике. Пример:
  77.  
  78.        def process_response(self, response):
  79.            if 'error' in response:
  80.                if response.error == 'need_captcha':
  81.                    ...
  82.                    self.authorize(None, None, captcha_key, captcha_sid)
  83.                    return
  84.            super().process_response(response)
  85.  
  86.        Либо можно переписать метод.
  87.        """
  88.         if 'error' in response:
  89.             raise AuthError(
  90.                 response.get('error_description') or response.error)
  91.         self.client.access_token = AccessToken(
  92.             key=response.access_token,
  93.             user_id=response.user_id,
  94.             expires_in=response.expires_in,
  95.             secret=response.get('secret')
  96.         )
  97.         self.logger.info("Successfully authorized")
  98.  
  99.  
  100. class ClientAuth(AuthMixin):
  101.     """Осуществляет авторизацию Standalone приложения
  102.    <https://vk.com/dev/auth_mobile>"""
  103.     auth_path = 'authorize'
  104.  
  105.     def __init__(self,
  106.                  client,
  107.                  client_id,
  108.                  scope=None,
  109.                  username=None,
  110.                  password=None,
  111.                  redirect_uri=REDIRECT_URI,
  112.                  display=None):
  113.         self.logger = logging.getLogger(
  114.             ".".join([self.__class__.__module__, self.__class__.__name__]))
  115.         self.client = client
  116.         self.client_id = client_id
  117.         self.username = username
  118.         self.password = password
  119.         self.redirect_uri = redirect_uri
  120.         self.scope = scope
  121.         self.display = display
  122.  
  123.     def authorize(self, username=None, password=None):
  124.         self.username = username or self.username
  125.         self.password = password or self.password
  126.         if not self.username or not self.password:
  127.             raise AuthError("Username and password are required")
  128.         params = dict(
  129.             client_id=self.client_id,
  130.             redirect_uri=self.redirect_uri,
  131.             v=self.client.api_version,
  132.             response_type='token'
  133.         )
  134.         if self.scope:
  135.             params['scope'] = self.scope
  136.         if self.display:
  137.             params['display'] = self.display
  138.         r = self.client.session.get(self.get_auth_url(params))
  139.         action = self.get_form_action(r.text)
  140.         params = self.get_login_form_params(r.text)
  141.         self.submit_login_form(action, params)
  142.  
  143.     def submit_login_form(self, action, params):
  144.         params['email'] = self.username
  145.         params['pass'] = self.password
  146.         r = self.client.session.post(action, params)
  147.         self.logger.debug("Current URL: %s", r.url)
  148.         if r.url.find('#'):
  149.             # Копипаст
  150.             h = r.url.split("#")[1]
  151.             res = dict(urllib.parse.parse_qsl(h))
  152.             assert 'access_token' in res
  153.             self.client.access_token = AccessToken(
  154.                 res['access_token'],
  155.                 int(res['user_id']),
  156.                 int(res['expires_in']),
  157.                 res.get('secret')
  158.             )
  159.             return
  160.         ga_match = re.search(
  161.             'https://login\.vk\.com/\?act=grant_access([^"]+)', r.text)
  162.         # Страница с подтверждением, где кнопочку Allow нужно нажать
  163.         if ga_match:
  164.             ga_url = ga_match.group(0)
  165.             r = self.client.session.get(ga_url)
  166.             h = r.url.split("#")[1]
  167.             res = dict(urllib.parse.parse_qsl(h))
  168.             if 'error' in res:
  169.                 raise AuthError(res.get('error_description') or res['error'])
  170.             assert 'access_token' in res
  171.             self.client.access_token = AccessToken(
  172.                 res['access_token'],
  173.                 int(res['user_id']),
  174.                 int(res['expires_in']),
  175.                 res.get('secret')
  176.             )
  177.             return
  178.         captcha_match = re.search(
  179.             '([^"]+/captcha\.php\?sid=(\d+)[^"]+)', r.text)
  180.         if captcha_match:
  181.             captcha_url, captcha_sid = captcha_match.groups()
  182.             try:
  183.                 captcha_key = self.get_captcha_key(captcha_url)
  184.             except NotImplementedError:
  185.                 raise AuthError("Captcha required")
  186.             params['captcha_sid'] = captcha_sid
  187.             params['captcha_key'] = captcha_key
  188.             # Хз можно, наверное, закомментировать. Все хеши к сессии привязаны
  189.             params = self.get_login_form_params(r.text)
  190.             self.submit_login_form(action, params)
  191.             return
  192.         error_match = re.search(
  193.             '(warning|error)">([^<]+)', r.text)
  194.         if error_match:
  195.             raise AuthError(error_match.group(2))
  196.         raise AuthError("WTF?")
  197.  
  198.     def get_captcha_key(self, url):
  199.         raise NotImplementedError
  200.  
  201.     def get_form_action(self, content):
  202.         match = re.search(' action="([^"]+)', content)
  203.         return match.group(1)
  204.  
  205.     def get_login_form_params(self, content):
  206.         matches = re.findall(
  207.             '(_origin|ip_h|lg_h|to|expire)" value="([^"]+)', content)
  208.         return dict(matches)
  209.  
  210.  
  211. class AuthError(Exception):
  212.     pass
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement