Skip to content

Commit 3ff6ee0

Browse files
committed
Add logging; Update VkApi.auth
1 parent 57ab2ce commit 3ff6ee0

2 files changed

Lines changed: 143 additions & 54 deletions

File tree

vk_api/exceptions.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@ class AccessDenied(VkApiError):
1919
pass
2020

2121

22-
class AuthorizationError(VkApiError): # todo: delete
22+
class AuthError(VkApiError):
2323
pass
2424

2525

26-
class AuthError(AuthorizationError):
26+
class AuthorizationError(AuthError): # todo: delete
27+
pass
28+
29+
30+
class PasswordRequired(AuthError):
2731
pass
2832

2933

vk_api/vk_api.py

Lines changed: 137 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Copyright (C) 2017
88
"""
99

10+
import logging
1011
import re
1112
import threading
1213
import time
@@ -36,27 +37,19 @@
3637

3738

3839
class VkApi(object):
39-
def __init__(self, login=None, password=None, number=None, sec_number=None,
40-
token=None,
41-
proxies=None,
40+
def __init__(self, login=None, password=None, token=None,
4241
auth_handler=None, captcha_handler=None,
43-
config=None, config_filename='vk_config.json',
42+
config=jconfig.Config, config_filename='vk_config.v2.json',
4443
api_version='5.63', app_id=2895443, scope=33554431,
4544
client_secret=None):
4645
"""
47-
:param login: Логин ВКонтакте
48-
:param password: Пароль ВКонтакте
49-
:param number: Номер для проверки безопасности (указывать, если
50-
в качестве логина используется не номер)
51-
:param sec_number: Часть номера, которая проверяется при проверке
52-
безопасности (указывать, если точно известно, что
53-
вводить и если автоматическое получение кода из
54-
номера работает не корректно)
46+
:param login: Логин ВКонтакте (лучше использовать номер телефона для
47+
автоматического обхода проверки безопасности)
48+
:param password: Пароль ВКонтакте (если пароль не передан, то будет
49+
попытка использовать сохраненные данные для
50+
аутентификации)
5551
5652
:param token: access_token
57-
:param proxies: proxy server
58-
{'http': 'http://127.0.0.1:8888/',
59-
'https': 'https://127.0.0.1:8888/'}
6053
:param auth_handler: Функция для обработки двухфакторной аутентификации,
6154
должна возвращать строку с кодом и
6255
булевое значение, означающее, стоит ли запомнить
@@ -74,8 +67,6 @@ def __init__(self, login=None, password=None, number=None, sec_number=None,
7467

7568
self.login = login
7669
self.password = password
77-
self.number = number
78-
self.sec_number = sec_number
7970

8071
self.sid = None
8172
self.token = {'access_token': token}
@@ -85,13 +76,9 @@ def __init__(self, login=None, password=None, number=None, sec_number=None,
8576
self.scope = scope
8677
self.client_secret = client_secret
8778

88-
if config is None:
89-
self.settings = jconfig.Config(login, filename=config_filename)
90-
else:
91-
self.settings = config(login, filename=config_filename)
79+
self.settings = config(self.login, filename=config_filename)
9280

9381
self.http = requests.Session()
94-
self.http.proxies = proxies
9582
self.http.headers.update({
9683
'User-agent': 'Mozilla/5.0 (Windows NT 6.1; rv:40.0) '
9784
'Gecko/20100101 Firefox/40.0'
@@ -108,27 +95,94 @@ def __init__(self, login=None, password=None, number=None, sec_number=None,
10895

10996
self.lock = threading.Lock()
11097

111-
def auth(self, reauth=False):
112-
""" Полная авторизация с получением токена
98+
self.logger = logging.getLogger('vk_api')
99+
100+
def auth(self, reauth=False, token_only=False):
101+
""" Аутентификация
113102
114103
:param reauth: Позволяет переавторизиваться, игнорируя сохраненные
115-
куки и токен
104+
куки и токен
105+
106+
:param token_only: Включает оптимальную стратегию аутентификации, если
107+
необходим только access_token
108+
109+
Например если сохраненные куки не валидны,
110+
но токен валиден, то аутентификация пройдет успешно
111+
112+
При token_only=False, сначала проверяется
113+
валидность куки. Если кука не будет валидна, то
114+
будет произведена попытка аутетификации с паролем.
115+
Тогда если пароль не верен или пароль не передан,
116+
то аутентификация закончится с ошибкой.
117+
118+
Если вы не делаете запросы к веб версии сайта
119+
используя куки, то лучше использовать
120+
token_only=True
116121
"""
117122

118-
if self.login and self.password:
119-
if reauth:
120-
self.settings.clear_section()
123+
if not self.login:
124+
self.logger.info('No login to auth')
125+
return
126+
127+
self.logger.info('Auth with login: {}'.format(self.login))
128+
129+
self.sid = self.settings.remixsid
130+
self.token = self.settings.setdefault('token', {}).get(str(self.scope))
131+
132+
if not token_only:
133+
self._auth_cookies(reauth=reauth)
134+
else:
135+
self._auth_token(reauth=reauth)
136+
137+
def _auth_cookies(self, reauth=False):
138+
139+
if reauth:
140+
self.logger.info('Auth forced')
141+
142+
self.settings.clear_section()
143+
144+
self.vk_login()
145+
self.api_login()
146+
return
147+
148+
if not self.check_sid():
149+
self.logger.info(
150+
'remixsid from config is not valid: {}'.format(
151+
self.sid
152+
)
153+
)
154+
155+
self.vk_login()
156+
else:
157+
self.security_check()
158+
159+
if not self.check_token():
160+
self.logger.info(
161+
'access_token from config is not valid: {}'.format(
162+
self.token
163+
)
164+
)
165+
166+
self.api_login()
167+
else:
168+
self.logger.info('access_token from config is valid')
169+
170+
def _auth_token(self, reauth=False):
121171

122-
self.sid = self.settings.remixsid
123-
self.token = self.settings.token
172+
if not reauth and self.check_token():
173+
self.logger.info('access_token from config is valid')
174+
return
124175

125-
if not self.check_sid():
126-
self.vk_login()
127-
else:
128-
self.security_check()
176+
if reauth:
177+
self.logger.info('Auth (API) forced')
129178

130-
if not self.check_token():
131-
self.api_login()
179+
if self.check_sid():
180+
self.security_check()
181+
self.api_login()
182+
183+
elif self.password:
184+
self.vk_login()
185+
self.api_login()
132186

133187
def authorization(self, *args, **kwargs):
134188
import warnings
@@ -144,6 +198,12 @@ def authorization(self, *args, **kwargs):
144198
def vk_login(self, captcha_sid=None, captcha_key=None):
145199
""" Авторизация ВКонтакте с получением cookies remixsid """
146200

201+
self.logger.info('Logging in...')
202+
203+
if not self.password:
204+
self.logger.info('No password')
205+
raise PasswordRequired('Password is required to login')
206+
147207
self.http.cookies.clear()
148208

149209
# Get cookies
@@ -160,6 +220,13 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
160220
}
161221

162222
if captcha_sid and captcha_key:
223+
self.logger.info(
224+
'Using captcha code: {}: {}'.format(
225+
captcha_sid,
226+
captcha_key
227+
)
228+
)
229+
163230
values.update({
164231
'captcha_sid': captcha_sid,
165232
'captcha_key': captcha_key
@@ -168,15 +235,20 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
168235
response = self.http.post('https://login.vk.com/', values)
169236

170237
if 'onLoginCaptcha(' in response.text:
238+
self.logger.info('Captcha code is required')
239+
171240
captcha_sid = search_re(RE_CAPTCHAID, response.text)
172241
captcha = Captcha(self, captcha_sid, self.vk_login)
173242

174243
return self.error_handlers[CAPTCHA_ERROR_CODE](captcha)
175244

176245
if 'onLoginFailed(4' in response.text:
246+
self.logger.info('Bad password')
177247
raise BadPassword('Bad password')
178248

179249
if 'act=authcheck' in response.text:
250+
self.logger.info('Two factor is required')
251+
180252
response = self.http.get('https://vk.com/login?act=authcheck')
181253

182254
self.twofactor(response)
@@ -187,6 +259,8 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
187259
)
188260

189261
if remixsid:
262+
self.logger.info('Got remixsid')
263+
190264
self.settings.remixsid = remixsid
191265

192266
# Нужно для авторизации в API
@@ -199,6 +273,8 @@ def vk_login(self, captcha_sid=None, captcha_key=None):
199273

200274
self.sid = remixsid
201275
else:
276+
self.logger.info('Unknown auth error')
277+
202278
raise AuthError(
203279
'Unknown error. Please send bugreport: https://vk.com/python273'
204280
)
@@ -236,20 +312,19 @@ def twofactor(self, auth_response):
236312
raise TwoFactorError('Two factor authentication failed')
237313

238314
def security_check(self, response=None):
315+
self.logger.info('Checking security check request')
316+
239317
if response is None:
240318
response = self.http.get('https://vk.com/settings')
241319
if 'security_check' not in response.url:
320+
self.logger.info('Security check is not required')
242321
return response
243322

244323
phone_prefix = clean_string(search_re(RE_PHONE_PREFIX, response.text))
245324
phone_postfix = clean_string(search_re(RE_PHONE_POSTFIX, response.text))
246325

247326
code = None
248-
if self.sec_number:
249-
code = self.sec_number
250-
elif self.number:
251-
code = code_from_number(phone_prefix, phone_postfix, self.number)
252-
elif self.login:
327+
if self.login:
253328
code = code_from_number(phone_prefix, phone_postfix, self.login)
254329

255330
if code:
@@ -277,18 +352,26 @@ def security_check(self, response=None):
277352
def check_sid(self):
278353
""" Проверка Cookies remixsid на валидность """
279354

280-
if self.sid:
281-
url = 'https://vk.com/feed2.php'
282-
self.http.cookies.update({
283-
'remixsid': self.sid,
284-
'remixlang': '0',
285-
'remixsslsid': '1'
286-
})
355+
self.logger.info('Checking remixsid...')
287356

288-
response = self.http.get(url).json()
357+
if not self.sid:
358+
self.logger.info('No remixsid')
359+
return
289360

290-
if response['user']['id'] != -1:
291-
return response
361+
url = 'https://vk.com/feed2.php'
362+
self.http.cookies.update({
363+
'remixsid': self.sid,
364+
'remixlang': '0',
365+
'remixsslsid': '1'
366+
})
367+
368+
response = self.http.get(url).json()
369+
370+
if response['user']['id'] != -1:
371+
self.logger.info('remixsid is valid')
372+
return response
373+
374+
self.logger.info('remixsid is not valid')
292375

293376
def api_login(self):
294377
""" Получение токена через Desktop приложение """
@@ -322,9 +405,11 @@ def api_login(self):
322405
x = i.split('=')
323406
token.update({x[0]: x[1]})
324407

325-
self.settings.token = token
408+
self.settings.setdefault('token', {})[str(self.scope)] = token
326409
self.settings.save()
327410
self.token = token
411+
412+
self.logger.info('Got access_token')
328413
else:
329414
raise AuthError('Authorization error (api)')
330415

0 commit comments

Comments
 (0)