diff --git a/.gitignore b/.gitignore index 4b28206..0ff52d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea build dist -src/*.egg-info \ No newline at end of file +src/*.egg-info +__pycache__ diff --git a/example/example_captcha.py b/example/example_captcha.py new file mode 100644 index 0000000..c6031d8 --- /dev/null +++ b/example/example_captcha.py @@ -0,0 +1,27 @@ +from __future__ import print_function + +try: + import vkaudiotoken +except ImportError: + import path_hack + +from vkaudiotoken import get_kate_token, get_vk_official_token, TokenException +import sys + +login = sys.argv[1] +password = sys.argv[2] +# for 2 factor authentication with sms +auth_code = sys.argv[3] if len(sys.argv) > 3 else 'GET_CODE' + +captcha_sid = None +captcha_key = None +while True: + try: + print(get_kate_token(login, password, auth_code, captcha_sid, captcha_key)) + break + except TokenException as err: + if err.code == TokenException.CAPTCHA_REQ and 'captcha_sid' in err.extra: + captcha_sid = err.extra['captcha_sid'] + captcha_key = input("Enter captcha key from image (" + err.extra["captcha_img"] + "): ") + else: + raise diff --git a/src/vkaudiotoken/CommonParams.py b/src/vkaudiotoken/CommonParams.py index 90df850..9dd1b27 100644 --- a/src/vkaudiotoken/CommonParams.py +++ b/src/vkaudiotoken/CommonParams.py @@ -22,6 +22,14 @@ def get_two_factor_part(self, code=None): ('force_sms', 1) ] + [] if code == 'GET_CODE' else [('code', code)] + def get_captcha(self, captcha_sid=None, captcha_key=None): + if captcha_sid is None or captcha_key is None: + return [] + return [ + ('captcha_sid', captcha_sid), + ('captcha_key', captcha_key) + ] + def generate_random_string(self, length, characters): return ''.join(random.choice(characters) for _ in range(length)) diff --git a/src/vkaudiotoken/TokenException.py b/src/vkaudiotoken/TokenException.py index d2ca3a8..4f0763a 100644 --- a/src/vkaudiotoken/TokenException.py +++ b/src/vkaudiotoken/TokenException.py @@ -5,6 +5,7 @@ class TokenException(Exception): REQUEST_ERR = 3 TWOFA_REQ = 4 TWOFA_ERR = 5 + CAPTCHA_REQ = 6 @property def extra(self): @@ -37,3 +38,6 @@ def __init__(self, code, extra=None): elif code == TokenException.TWOFA_ERR: super(TokenException, self).__init__( "2FA Error. Code: {0}. Error extra: {1}".format(code, extrastr)) + elif code == TokenException.CAPTCHA_REQ: + super(TokenException, self).__init__( + "Captcha needed. Code: {0}. Error extra: {1}".format(code, extrastr)) diff --git a/src/vkaudiotoken/TokenReceiver.py b/src/vkaudiotoken/TokenReceiver.py index 2253622..cfb35be 100644 --- a/src/vkaudiotoken/TokenReceiver.py +++ b/src/vkaudiotoken/TokenReceiver.py @@ -4,12 +4,14 @@ class TokenReceiver: - def __init__(self, login, password, auth_data, params, auth_code=None, scope='audio,offline'): + def __init__(self, login, password, auth_data, params, auth_code=None, captcha_sid=None, captcha_key=None, scope='audio,offline'): self._params = params self._login = login self._password = password self._auth_code = auth_code self._auth_data = auth_data + self._captcha_sid = captcha_sid + self._captcha_key = captcha_key self._scope = scope self._client = KATE @@ -61,17 +63,21 @@ def _get_non_refreshed(self): self._params.set_common_vk(session) dec = session.get('https://oauth.vk.com/token', params=[ - ('grant_type', 'password'), - ('client_id', self._client.client_id), - ('client_secret', self._client.client_secret), - ('username', self._login), - ('password', self._password), - ('v', '5.95'), - ('lang', 'en'), - ('scope', self._scope) - ] + self._params.get_two_factor_part(self._auth_code)).json() - if 'error' in dec and dec['error'] == 'need_validation': - raise TokenException(TokenException.TWOFA_REQ, dec) + ('grant_type', 'password'), + ('client_id', self._client.client_id), + ('client_secret', self._client.client_secret), + ('username', self._login), + ('password', self._password), + ('v', '5.95'), + ('lang', 'en'), + ('scope', self._scope) + ] + self._params.get_two_factor_part(self._auth_code) + + self._params.get_captcha(self._captcha_sid, self._captcha_key)).json() + if 'error' in dec: + if dec['error'] == 'need_validation': + raise TokenException(TokenException.TWOFA_REQ, dec) + if dec['error'] == 'need_captcha': + raise TokenException(TokenException.CAPTCHA_REQ, dec) if 'user_id' not in dec: raise TokenException(TokenException.TOKEN_NOT_RECEIVED, dec) return dec['access_token'] diff --git a/src/vkaudiotoken/TokenReceiverOfficial.py b/src/vkaudiotoken/TokenReceiverOfficial.py index f88fd9e..e5ec8cd 100644 --- a/src/vkaudiotoken/TokenReceiverOfficial.py +++ b/src/vkaudiotoken/TokenReceiverOfficial.py @@ -4,11 +4,13 @@ class TokenReceiverOfficial: - def __init__(self, login, password, params, auth_code=None, scope='all'): + def __init__(self, login, password, params, auth_code=None, captcha_sid=None, captcha_key=None, scope='all'): self._login = login self._password = password self._params = params self._auth_code = auth_code + self._captcha_sid = captcha_sid + self._captcha_key = captcha_key self._scope = scope self._client = VK_OFFICIAL @@ -21,19 +23,23 @@ def _get_non_refreshed(self): device_id = self._params.generate_random_string(16, '0123456789abcdef') dec = session.get('https://oauth.vk.com/token', params=[ - ('grant_type', 'password'), - ('client_id', self._client.client_id), - ('client_secret', self._client.client_secret), - ('username', self._login), - ('password', self._password), - ('v', '5.116'), - ('lang', 'en'), - ('scope', self._scope), - ('device_id', device_id) - ] + self._params.get_two_factor_part(self._auth_code)).json() + ('grant_type', 'password'), + ('client_id', self._client.client_id), + ('client_secret', self._client.client_secret), + ('username', self._login), + ('password', self._password), + ('v', '5.116'), + ('lang', 'en'), + ('scope', self._scope), + ('device_id', device_id) + ] + self._params.get_two_factor_part(self._auth_code) + + self._params.get_captcha(self._captcha_sid, self._captcha_key)).json() - if 'error' in dec and dec['error'] == 'need_validation': - raise TokenException(TokenException.TWOFA_REQ, dec) + if 'error' in dec: + if dec['error'] == 'need_validation': + raise TokenException(TokenException.TWOFA_REQ, dec) + if dec['error'] == 'need_captcha': + raise TokenException(TokenException.CAPTCHA_REQ, dec) if 'user_id' not in dec: raise TokenException(TokenException.TOKEN_NOT_RECEIVED, dec) return {'access_token': dec['access_token']} diff --git a/src/vkaudiotoken/__init__.py b/src/vkaudiotoken/__init__.py index 66e4b9f..5369928 100644 --- a/src/vkaudiotoken/__init__.py +++ b/src/vkaudiotoken/__init__.py @@ -12,7 +12,7 @@ from . import supported_clients -def get_kate_token(login, password, auth_code='GET_CODE', non_refreshed_token=None): +def get_kate_token(login, password, auth_code='GET_CODE', captcha_sid=None, captcha_key=None, non_refreshed_token=None): params = CommonParams(supported_clients.KATE.user_agent) protobuf_helper = SmallProtobufHelper() @@ -22,13 +22,13 @@ def get_kate_token(login, password, auth_code='GET_CODE', non_refreshed_token=No mtalkClient = MTalkClient(auth_data, protobuf_helper) mtalkClient.send_request() - receiver = TokenReceiver(login, password, auth_data, params, auth_code) + receiver = TokenReceiver(login, password, auth_data, params, auth_code, captcha_sid, captcha_key) return {'token': receiver.get_token(non_refreshed_token), 'user_agent': supported_clients.KATE.user_agent} -def get_vk_official_token(login, password, auth_code='GET_CODE'): +def get_vk_official_token(login, password, auth_code='GET_CODE', captcha_sid=None, captcha_key=None): params = CommonParams(supported_clients.VK_OFFICIAL.user_agent) - receiver = TokenReceiverOfficial(login, password, params, auth_code) + receiver = TokenReceiverOfficial(login, password, params, auth_code, captcha_sid, captcha_key) return { 'token': receiver.get_token()['access_token'],