99"""
1010
1111import re
12- import time
1312import threading
13+ import time
1414
1515import requests
1616
1717import jconfig
18+ from .utils import code_from_number , search_re , clean_string
19+
1820
1921DELAY = 0.34 # ~3 requests per second
2022TOO_MANY_RPS_CODE = 6
2931RE_AUTH_HASH = re .compile (r"hash: '([a-z_0-9]+)'" )
3032RE_TOKEN_URL = re .compile (r'location\.href = "(.*?)"\+addr;' )
3133
32- RE_PHONE_PREFIX = re .compile (r'phone_number">(.*?)<' )
33- RE_PHONE_PREFIX_2 = re .compile (r'label ta_r">\+(\d+)' )
34+ RE_PHONE_PREFIX = re .compile (r'label ta_r">\+(.*?)<' )
3435RE_PHONE_POSTFIX = re .compile (r'phone_postfix">.*?(\d+).*?<' )
3536
3637
@@ -134,6 +135,7 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
134135 response = self .http .get ('https://vk.com/' )
135136
136137 values = {
138+ 'act' : 'login' ,
137139 'role' : 'al_frame' ,
138140 '_origin' : 'https://vk.com' ,
139141 'utf8' : '1' ,
@@ -148,18 +150,26 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
148150 'captcha_key' : captcha_key
149151 })
150152
151- response = self .http .post ('https://login.vk.com/?act=login' , values )
153+ response = self .http .post ('https://login.vk.com/' , values )
154+
155+ if 'onLoginCaptcha(' in response .text :
156+ captcha_sid = search_re (RE_CAPTCHAID , response .text )
157+ captcha = Captcha (self , captcha_sid , self .vk_login )
158+
159+ return self .error_handlers [CAPTCHA_ERROR_CODE ](captcha )
160+
161+ if 'onLoginFailed(4' in response .text :
162+ raise BadPassword ('Bad password' )
152163
153- remixsid = None
164+ if 'act=authcheck' in response .text :
165+ response = self .http .get ('https://vk.com/login?act=authcheck' )
154166
155- if 'act=authcheck' in response .url : # TODO: test/fix
156- code , remember_device = self .error_handlers [TWOFACTOR_CODE ]()
157- response = self .twofactor (response , code , remember_device )
167+ self .twofactor (response )
158168
159- if ' remixsid' in self . http . cookies :
160- remixsid = self .http .cookies [ 'remixsid' ]
161- elif 'remixsid6' in self .http .cookies : # ipv6?
162- remixsid = self . http . cookies [ 'remixsid6' ]
169+ remixsid = (
170+ self .http .cookies . get ( 'remixsid' ) or
171+ self .http .cookies . get ( 'remixsid6' )
172+ )
163173
164174 if remixsid :
165175 self .settings .remixsid = remixsid
@@ -173,66 +183,51 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
173183 self .settings .save ()
174184
175185 self .sid = remixsid
176-
177- elif 'onLoginCaptcha(' in response .text :
178- captcha_sid = search_re (RE_CAPTCHAID , response .text )
179- captcha = Captcha (self , captcha_sid , self .vk_login )
180-
181- if self .error_handlers [CAPTCHA_ERROR_CODE ]:
182- return self .error_handlers [CAPTCHA_ERROR_CODE ](captcha )
183- else :
184- raise AuthorizationError ('Authorization error (capcha)' )
185- elif 'onLoginFailed(4' in response .text :
186- raise BadPassword ('Bad password' )
187186 else :
188187 raise AuthorizationError (
189188 'Unknown error. Please send bugreport: https://vk.com/python273'
190189 )
191190
192- self .security_check ()
191+ response = self .security_check ()
193192
194- if 'act=blocked' in response .url : # TODO: text/fix
193+ if 'act=blocked' in response .url :
195194 raise AccountBlocked ('Account is blocked' )
196195
197- def twofactor (self , response , code , remember_device = False ):
196+ def twofactor (self , auth_response ):
198197 """ Двухфакторная аутентификация
199- :param reponse: запрос, содержащий страницу с приглашением к аутентификации
200- :param code: код, который необходимо ввести для успешной аутентификации
201- :param remember_device: параметр, означающий,
202- стоит ли запоминать это устройство в целях
203- избежания повторного ввода кода(default: False)
198+ :param auth_response: страница с приглашением к аутентификации
204199 """
200+ code , remember_device = self .error_handlers [TWOFACTOR_CODE ]()
205201
206- if code == None :
207- raise TwoFactorError ("Empty code doesn't acceptable" )
208- if len (code ) != 6 :
209- raise TwoFactorError ("Length of code cannot be other than 6." )
202+ auth_hash = search_re (RE_AUTH_HASH , auth_response .text )
210203
211- auth_hash = search_re (RE_AUTH_HASH , response .text )
212- url = 'https://vk.com/al_login.php'
213- if auth_hash :
214- values = {
215- 'act' : 'a_authcheck_code' ,
216- 'code' : code ,
217- 'remember' : int (remember_device ),
218- 'hash' : auth_hash ,
219- }
220- response = self .http .post (url , values , cookies = response .cookies )
221- if url not in response .url :
222- return response
223- raise TwoFactorError ('Incorrect code: %s' % code )
204+ values = {
205+ 'act' : 'a_authcheck_code' ,
206+ 'al' : '1' ,
207+ 'code' : code ,
208+ 'remember' : int (remember_device ),
209+ 'hash' : auth_hash ,
210+ }
211+
212+ response = self .http .post ('https://vk.com/al_login.php' , values )
213+ response_parsed = response .text .split ('<!>' )
214+
215+ if response_parsed [4 ] == '4' : # OK
216+ return self .http .get ('https://vk.com/' + response_parsed [5 ])
217+
218+ elif response_parsed [4 ] == '8' : # Incorrect code
219+ return self .twofactor (auth_response )
220+
221+ raise TwoFactorError ('Two factor authentication failed' )
224222
225223 def security_check (self , response = None ):
226224 if response is None :
227225 response = self .http .get ('https://vk.com/settings' )
228226 if 'security_check' not in response .url :
229- return
230-
231- phone_prefix = search_re (RE_PHONE_PREFIX , response .text )
232- if not phone_prefix :
233- phone_prefix = search_re (RE_PHONE_PREFIX_2 , response .text )
227+ return response
234228
235- phone_postfix = search_re (RE_PHONE_POSTFIX , response .text )
229+ phone_prefix = clean_string (search_re (RE_PHONE_PREFIX , response .text ))
230+ phone_postfix = clean_string (search_re (RE_PHONE_POSTFIX , response .text ))
236231
237232 code = None
238233 if self .sec_number :
@@ -257,12 +252,12 @@ def security_check(self, response=None):
257252 response = self .http .post ('https://vk.com/login.php' , values )
258253
259254 if response .text .split ('<!>' )[4 ] == '4' :
260- return True
255+ return response
261256
262257 if phone_prefix and phone_postfix :
263258 raise SecurityCheck (phone_prefix , phone_postfix )
264- else :
265- raise SecurityCheck (response = response )
259+
260+ raise SecurityCheck (response = response )
266261
267262 def check_sid (self ):
268263 """ Проверка Cookies remixsid на валидность """
@@ -457,54 +452,6 @@ def __getattr__(self, method):
457452 def __call__ (self , * args , ** kwargs ):
458453 return self ._vk .method (self ._method , kwargs )
459454
460- def get_doc (self ):
461- doc (self ._method )
462-
463-
464- def doc (method = None ):
465- """ Открывает документацию на метод или список всех методов
466-
467- :param method: метод
468- """
469-
470- if not method :
471- method = 'methods'
472-
473- url = 'https://vk.com/dev/{}' .format (method )
474-
475- import webbrowser
476- webbrowser .open (url )
477-
478-
479- def search_re (reg , string ):
480- """ Поиск по регулярке """
481- s = reg .search (string )
482-
483- if s :
484- groups = s .groups ()
485- return groups [0 ]
486-
487-
488- def code_from_number (phone_prefix , phone_postfix , number ):
489- prefix_len = len (phone_prefix )
490- postfix_len = len (phone_postfix )
491-
492- if number [0 ] == '+' :
493- number = number [1 :]
494-
495- if (prefix_len + postfix_len ) >= len (number ):
496- return
497-
498- # Сравниваем начало номера
499- if not number [:prefix_len ] == phone_prefix :
500- return
501-
502- # Сравниваем конец номера
503- if not number [- postfix_len :] == phone_postfix :
504- return
505-
506- return number [prefix_len :- postfix_len ]
507-
508455
509456class AuthorizationError (Exception ):
510457 pass
0 commit comments