Advertisement
stuppid_bot

Untitled

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