def test_parse_url_query_params(self): resp_url = 'https://m.vk.com/login.php?act=security_check&to=&al_page=' params = utils.parse_url_query_params(resp_url, fragment=False) self.assertEqual(params['act'], 'security_check') resp_url = '/login.php?act=security_check&to=&hash=4b07a4650e9f22038b' params = utils.parse_url_query_params(resp_url, fragment=False) self.assertEqual(params['act'], 'security_check') self.assertEqual(params['hash'], '4b07a4650e9f22038b')
def test_parse_url_fragments_params(self): url = 'https://oauth.vk.com/blank.html#access_token=337d6dc7cd73ff0040' \ '&expires_in=0&user_id=12345' params = utils.parse_url_query_params(url) self.assertEqual(params['access_token'], '337d6dc7cd73ff0040') self.assertEqual(params['expires_in'], '0') self.assertEqual(params['user_id'], '12345')
def require_phone_number(self, html, session): logger.info( 'Auth requires phone number. You do login from unusual place') # Raises VkPageWarningsError in case of warnings # NOTE: we check only 'security_check' case on warnings for now # in future it might be propagated to other cases as well check_html_warnings(html=html) # Determine form action url action_url = parse_form_action_url(html) # Get masked phone from html to make things more clear phone_prefix, phone_suffix = parse_masked_phone_number(html) if self._phone_number: code = self._phone_number[len(phone_prefix):-len(phone_suffix)] else: prompt = 'Enter missing digits of your phone number (%s****%s): '\ % (phone_prefix, phone_suffix) code = raw_input(prompt) params = parse_url_query_params(action_url, fragment=False) auth_data = { 'code': code, 'act': 'security_check', 'hash': params['hash'] } response = session.post(url=self.LOGIN_URL + action_url, data=auth_data) logger.debug('require_phone_number resp: %s', response.text)
def require_phone_number(self, html, session): logger.info( 'Auth requires phone number. You do login from unusual place') # Raises VkPageWarningsError in case of warnings # NOTE: we check only 'security_check' case on warnings for now # in future it might be propagated to other cases as well check_html_warnings(html=html) # Determine form action url action_url = parse_form_action_url(html) # Get masked phone from html to make things more clear phone_prefix, phone_suffix = parse_masked_phone_number(html) if self._phone_number: code = self._phone_number[len(phone_prefix):-len(phone_suffix)] else: prompt = 'Enter missing digits of your phone number (%s****%s): '\ % (phone_prefix, phone_suffix) code = raw_input(prompt) params = parse_url_query_params(action_url, fragment=False) auth_data = { 'code': code, 'act': 'security_check', 'hash': params['hash']} response = session.post( url=self.LOGIN_URL + action_url, data=auth_data) logger.debug('require_phone_number resp: %s', response.text)
def do_implicit_flow_authorization(self, session): """ Standard OAuth2 authorization method. It's used for getting access token More info: https://vk.com/dev/implicit_flow_user """ logger.info('Doing implicit flow authorization, app_id=%s', self.app_id) auth_data = { 'client_id': self.app_id, 'display': 'mobile', 'response_type': 'token', 'scope': self.scope, 'redirect_uri': 'https://oauth.vk.com/blank.html', 'v': self.api_version } response = session.post(url=self.AUTHORIZE_URL, data=stringify_values(auth_data)) url_query_params = parse_url_query_params(response.url) if 'expires_in' in url_query_params: logger.info('Token will be expired in %s sec.' % url_query_params['expires_in']) if 'access_token' in url_query_params: return url_query_params # Permissions are needed logger.info('Getting permissions') action_url = parse_form_action_url(response.text) logger.debug('Response form action: %s', action_url) if action_url: response = session.get(action_url) url_query_params = parse_url_query_params(response.url) return url_query_params try: response_json = response.json() except ValueError: # not JSON in response error_message = 'OAuth2 grant access error' logger.error(response.text) else: error_message = 'VK error: [{}] {}'.format( response_json['error'], response_json['error_description']) logger.error('Permissions obtained') raise VkAuthError(error_message)
def do_oauth2_authorization(self, session): """ OAuth2. More info: https://vk.com/dev/auth_mobile """ logger.info('Doing oauth2') auth_data = { 'client_id': self.app_id, 'display': 'mobile', 'response_type': 'token', 'scope': self.scope, 'v': self.api_version } response = session.post(url=self.AUTHORIZE_URL, data=stringify_values(auth_data)) url_query_params = parse_url_query_params(response.url) if 'expires_in' in url_query_params: logger.info('Token will be expired in %s sec.' % url_query_params['expires_in']) if 'access_token' in url_query_params: return url_query_params # Permissions are needed logger.info('Getting permissions') action_url = parse_form_action_url(response.text) logger.debug('Response form action: %s', action_url) if action_url: response = session.get(action_url) url_query_params = parse_url_query_params(response.url) return url_query_params try: response_json = response.json() except ValueError: # not JSON in response error_message = 'OAuth2 grant access error' logger.error(response.text) else: error_message = 'VK error: [{}] {}'.format( response_json['error'], response_json['error_description']) logger.error('Permissions obtained') raise VkAuthError(error_message)
def do_oauth2_authorization(self, session): """ OAuth2. More info: https://vk.com/dev/auth_mobile """ logger.info('Doing oauth2') auth_data = { 'client_id': self.app_id, 'display': 'mobile', 'response_type': 'token', 'scope': self.scope, 'v': self.api_version } response = session.post(url=self.AUTHORIZE_URL, data=stringify_values(auth_data)) url_query_params = parse_url_query_params(response.url) if 'expires_in' in url_query_params: logger.info('Token will be expired in %s sec.' % url_query_params['expires_in']) if 'access_token' in url_query_params: return url_query_params # Permissions is needed logger.info('Getting permissions') form_action = parse_form_action_url(response.text) logger.debug('Response form action: %s', form_action) if form_action: response = session.get(form_action) url_query_params = parse_url_query_params(response.url) return url_query_params try: response_json = response.json() except ValueError: # not JSON in response error_message = 'OAuth2 grant access error' logger.error(response.text) else: error_message = 'VK error: [{}] {}'.format( response_json['error'], response_json['error_description']) logger.error('Permissions obtained') raise VkAuthError(error_message)
def do_login(self, http_session): """Do vk login :param http_session: vk_requests.utils.VerboseHTTPSession: http session """ response = http_session.get(self.LOGIN_URL) action_url = parse_form_action_url(response.text) # Stop login it action url is not found if not action_url: logger.debug(response.text) raise VkParseError("Can't parse form action url") login_form_data = {'email': self._login, 'pass': self._password} login_response = http_session.post(action_url, login_form_data) logger.debug('Cookies: %s', http_session.cookies) response_url_query = parse_url_query_params(login_response.url, fragment=False) logger.debug('response_url_query: %s', response_url_query) act = response_url_query.get('act') # Check response url query params firstly if 'sid' in response_url_query: self.require_auth_captcha(query_params=response_url_query, form_text=login_response.text, login_form_data=login_form_data, http_session=http_session) elif act == 'authcheck': self.require_2fa(html=login_response.text, http_session=http_session) elif act == 'security_check': self.require_phone_number(html=login_response.text, session=http_session) session_cookies = ('remixsid' in http_session.cookies, 'remixsid6' in http_session.cookies) if any(session_cookies): logger.info('VK session is established') return True else: message = 'Authorization error: incorrect password or ' \ 'authentication code' logger.error(message) raise VkAuthError(message)
def do_login(self, session): """Do vk login :param session: vk_requests.utils.VerboseHTTPSession: http session """ response = session.get(self.LOGIN_URL) action_url = parse_form_action_url(response.text) # Stop login it action url is not found if not action_url: logger.debug(response.text) raise VkParseError("Can't parse form action url") login_form_data = {'email': self._login, 'pass': self._password} login_response = session.post(action_url, login_form_data) logger.debug('Cookies: %s', session.cookies) response_url_query = parse_url_query_params( login_response.url, fragment=False) act = response_url_query.get('act') logger.debug('response_url_query: %s', response_url_query) # Check response url query params firstly if 'sid' in response_url_query: self.require_auth_captcha( query_params=response_url_query, form_text=login_response.text, login_form_data=login_form_data, session=session) elif act == 'authcheck': self.require_2fa(html=login_response.text, session=session) elif act == 'security_check': self.require_phone_number(html=login_response.text, session=session) session_cookies = ('remixsid' in session.cookies, 'remixsid6' in session.cookies) if any(session_cookies): logger.info('Session is already established') return None else: message = 'Authorization error: incorrect password or ' \ 'authentication code' logger.error(message) raise VkAuthError(message)
def do_login(self, session): """Do vk login :param session: vk_requests.utils.LoggingSession: http session """ response = session.get(self.LOGIN_URL) login_form_action = parse_form_action_url(response.text) if not login_form_action: raise VkAuthError('VK changed login flow') login_form_data = {'email': self._login, 'pass': self._password} response = session.post(login_form_action, login_form_data) logger.debug('Cookies: %s', session.cookies) response_url_query = parse_url_query_params( response.url, fragment=False) act = response_url_query.get('act') logger.debug('response_url_query: %s', response_url_query) # Check response url query params firstly if 'sid' in response_url_query: self.require_auth_captcha( query_params=response_url_query, form_text=response.text, login_form_data=login_form_data, session=session) elif act == 'authcheck': self.require_sms_code(html=response.text, session=session) elif act == 'security_check': self.require_phone_number(html=response.text, session=session) session_cookies = ('remixsid' in session.cookies, 'remixsid6' in session.cookies) if any(session_cookies): # Session is already established logger.info('Session is already established') return None else: message = 'Authorization error (incorrect password)' logger.error(message) raise VkAuthError(message)
def do_login(self, session): """Do vk login :param session: vk_requests.utils.LoggingSession: http session """ response = session.get(self.LOGIN_URL) login_form_action = parse_form_action_url(response.text) if not login_form_action: raise VkAuthError('VK changed login flow') login_form_data = {'email': self._login, 'pass': self._password} response = session.post(login_form_action, login_form_data) logger.debug('Cookies: %s', session.cookies) response_url_query = parse_url_query_params(response.url, fragment=False) act = response_url_query.get('act') logger.debug('response_url_query: %s', response_url_query) # Check response url query params firstly if 'sid' in response_url_query: self.require_auth_captcha(query_params=response_url_query, form_text=response.text, login_form_data=login_form_data, session=session) elif act == 'authcheck': self.require_sms_code(html=response.text, session=session) elif act == 'security_check': self.require_phone_number(html=response.text, session=session) session_cookies = ('remixsid' in session.cookies, 'remixsid6' in session.cookies) if any(session_cookies): # Session is already established logger.info('Session is already established') return None else: message = 'Authorization error (incorrect password)' logger.error(message) raise VkAuthError(message)