Skip to content

Commit 744a4ef

Browse files
committed
Implemented two-factor authentication.
1 parent 36cff03 commit 744a4ef

1 file changed

Lines changed: 39 additions & 2 deletions

File tree

vk_api/vk_api.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
CAPTCHA_ERROR_CODE = 14
2121
NEED_VALIDATION_CODE = 17
2222
HTTP_ERROR_CODE = -1
23+
TWOFACTOR_CODE = 666
2324

2425
RE_LOGIN_HASH = re.compile(r'name="lg_h" value="([a-z0-9]+)"')
2526
RE_CAPTCHAID = re.compile(r'sid=(\d+)')
2627
RE_NUMBER_HASH = re.compile(r"al_page: '3', hash: '([a-z0-9]+)'")
28+
RE_AUTH_HASH = re.compile(r"hash: '([a-z_0-9]+)'")
2729
RE_TOKEN_URL = re.compile(r'location\.href = "(.*?)"\+addr;')
2830

2931
RE_PHONE_PREFIX = re.compile(r'phone_number">(.*?)<')
@@ -34,7 +36,7 @@
3436
class VkApi(object):
3537
def __init__(self, login=None, password=None, number=None, sec_number=None,
3638
token=None,
37-
proxies=None, captcha_handler=None, config_filename='vk_config.json',
39+
proxies=None, auth_handler=None, captcha_handler=None, config_filename='vk_config.json',
3840
api_version='5.35', app_id=2895443, scope=33554431,
3941
client_secret=None):
4042
"""
@@ -51,6 +53,9 @@ def __init__(self, login=None, password=None, number=None, sec_number=None,
5153
:param proxies: proxy server
5254
{'http': 'http://127.0.0.1:8888/',
5355
'https': 'https://127.0.0.1:8888/'}
56+
:param auth_handler: Функция для обработки двухфакторной аутентификации,
57+
обязана возвращать строку с кодом для
58+
прохождения аутентификации
5459
:param captcha_handler: Функция для обработки капчи
5560
:param config_filename: Расположение config файла
5661
@@ -88,7 +93,8 @@ def __init__(self, login=None, password=None, number=None, sec_number=None,
8893
self.error_handlers = {
8994
NEED_VALIDATION_CODE: self.need_validation_handler,
9095
CAPTCHA_ERROR_CODE: captcha_handler or self.captcha_handler,
91-
TOO_MANY_RPS_CODE: self.too_many_rps_handler
96+
TOO_MANY_RPS_CODE: self.too_many_rps_handler,
97+
TWOFACTOR_CODE: auth_handler or self.auth_handler
9298
}
9399

94100
def authorization(self, reauth=False):
@@ -139,6 +145,10 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
139145

140146
remixsid = None
141147

148+
if 'act=authcheck' in response.url:
149+
code = self.error_handlers[TWOFACTOR_CODE]()
150+
response = self.twofactor(response, code)
151+
142152
if 'remixsid' in self.http.cookies:
143153
remixsid = self.http.cookies['remixsid']
144154
elif 'remixsid6' in self.http.cookies: # ipv6?
@@ -176,6 +186,28 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
176186
if 'act=blocked' in response.url:
177187
raise AccountBlocked('Account is blocked')
178188

189+
def twofactor(self, response, code):
190+
""" Двухфакторная аутентификация
191+
:param reponse: запрос, содержащий страницу с приглашением к аутентификации
192+
:param code: код, который необходимо ввести для успешной аутентификации
193+
"""
194+
assert code != None, "Empty code doesn't acceptable"
195+
assert len(code) == 6, "Length of code cannot be other than 6."
196+
197+
auth_hash = search_re(RE_AUTH_HASH, response.text)
198+
url = 'https://vk.com/al_login.php'
199+
if auth_hash:
200+
values = {
201+
'act': 'a_authcheck_code',
202+
'code': code,
203+
'remember': 0, # TODO: Fix me(device remembering)
204+
'hash': auth_hash,
205+
}
206+
response = self.http.post(url, values, cookies=response.cookies)
207+
if url not in response.url:
208+
return response
209+
raise TwoFactorError('Incorrect code: %s' % code)
210+
179211
def security_check(self, url=None, response=None):
180212
if url:
181213
response = self.http.get(url)
@@ -314,6 +346,9 @@ def too_many_rps_handler(self, error):
314346
time.sleep(0.5)
315347
error.try_method()
316348

349+
def auth_handler(self):
350+
raise AuthorizationError("No handler for two-factor authorization.")
351+
317352
def method(self, method, values=None, captcha_sid=None, captcha_key=None):
318353
""" Использование методов API
319354
@@ -442,6 +477,8 @@ class BadPassword(AuthorizationError):
442477
class AccountBlocked(AuthorizationError):
443478
pass
444479

480+
class TwoFactorError(AuthorizationError):
481+
pass
445482

446483
class SecurityCheck(AuthorizationError):
447484
def __init__(self, phone_prefix, phone_postfix, response=None):

0 commit comments

Comments
 (0)