├── requirements.txt ├── .gitignore ├── example ├── path_hack.py ├── usage │ ├── path_hack.py │ ├── example_kate.py │ └── example_vkofficial.py ├── example_simple.py ├── example_vkofficial.py ├── example_microg.py ├── example_twofahelper.py └── example_droidguard_str.py ├── src └── vkaudiotoken │ ├── supported_clients.py │ ├── VkClient.py │ ├── MTalkException.py │ ├── TwoFAHelper.py │ ├── ProtobufException.py │ ├── AndroidCheckin.py │ ├── MTalkClient.py │ ├── CommonParams.py │ ├── __init__.py │ ├── TokenException.py │ ├── TokenReceiverOfficial.py │ ├── TokenReceiver.py │ └── SmallProtobufHelper.py ├── LICENSE ├── setup.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | requests -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | build 3 | dist 4 | src/*.egg-info -------------------------------------------------------------------------------- /example/path_hack.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import os 3 | import sys 4 | 5 | currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 6 | packagedir = os.path.join(os.path.dirname(currentdir), 'src') 7 | sys.path.insert(0, packagedir) 8 | -------------------------------------------------------------------------------- /example/usage/path_hack.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import os 3 | import sys 4 | 5 | currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 6 | packagedir = os.path.join(os.path.dirname(currentdir), '..', 'src') 7 | sys.path.insert(0, packagedir) 8 | -------------------------------------------------------------------------------- /src/vkaudiotoken/supported_clients.py: -------------------------------------------------------------------------------- 1 | from .VkClient import VkClient 2 | 3 | KATE = VkClient( 4 | u'KateMobileAndroid/56 lite-460 (Android 4.4.2; SDK 19; x86; unknown Android SDK built for x86; en)', 5 | u'lxhD8OD7dMsqtXIm5IUY', 6 | u'2685278' 7 | ) 8 | 9 | VK_OFFICIAL = VkClient( 10 | u'VKAndroidApp/5.52-4543 (Android 5.1.1; SDK 22; x86_64; unknown Android SDK built for x86_64; en; 320x240)', 11 | u'hHbZxrka2uZ6jB1inYsH', 12 | u'2274003' 13 | ) 14 | -------------------------------------------------------------------------------- /example/example_simple.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | try: 4 | import vkaudiotoken 5 | except ImportError: 6 | import path_hack 7 | 8 | from vkaudiotoken import get_kate_token, get_vk_official_token 9 | import sys 10 | 11 | login = sys.argv[1] 12 | password = sys.argv[2] 13 | # for 2 factor authentication with sms 14 | auth_code = sys.argv[3] if len(sys.argv) > 3 else 'GET_CODE' 15 | 16 | print(get_kate_token(login, password, auth_code)) 17 | print(get_vk_official_token(login, password, auth_code)) -------------------------------------------------------------------------------- /src/vkaudiotoken/VkClient.py: -------------------------------------------------------------------------------- 1 | class VkClient(object): 2 | def __init__(self, user_agent, client_secret, client_id): 3 | self._user_agent = user_agent 4 | self._client_secret = client_secret 5 | self._client_id = client_id 6 | 7 | @property 8 | def user_agent(self): 9 | return self._user_agent 10 | 11 | @property 12 | def client_secret(self): 13 | return self._client_secret 14 | 15 | @property 16 | def client_id(self): 17 | return self._client_id 18 | -------------------------------------------------------------------------------- /src/vkaudiotoken/MTalkException.py: -------------------------------------------------------------------------------- 1 | class MTalkException(Exception): 2 | WRONG_RESPONSE = 1 3 | 4 | @property 5 | def extra(self): 6 | return self._extra 7 | 8 | @property 9 | def code(self): 10 | return self._code 11 | 12 | def __init__(self, code, extra=None): 13 | self._extra = extra 14 | self._code = code 15 | if code == MTalkException.WRONG_RESPONSE: 16 | super(MTalkException, self).__init__('Wrong response code {0}. Code: {1}'.format(extra, code)) 17 | -------------------------------------------------------------------------------- /example/example_vkofficial.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | try: 4 | import vkaudiotoken 5 | except ImportError: 6 | import path_hack 7 | 8 | from vkaudiotoken import CommonParams, TokenReceiverOfficial, supported_clients 9 | import sys 10 | 11 | login = sys.argv[1] 12 | password = sys.argv[2] 13 | # for 2 factor authentication with sms, or pass GET_CODE to get code 14 | auth_code = sys.argv[3] if len(sys.argv) > 3 else None 15 | 16 | params = CommonParams(supported_clients.VK_OFFICIAL.user_agent) 17 | receiver = TokenReceiverOfficial(login, password, params, auth_code) 18 | 19 | print(receiver.get_token()['access_token']) 20 | -------------------------------------------------------------------------------- /src/vkaudiotoken/TwoFAHelper.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from .TokenException import TokenException 3 | 4 | 5 | class TwoFAHelper: 6 | def __init__(self, params): 7 | self._params = params 8 | 9 | def validate_phone(self, validation_sid): 10 | session = requests.session() 11 | self._params.set_common_vk(session) 12 | dec = session.get("https://api.vk.com/method/auth.validatePhone", params=[ 13 | ('sid', validation_sid), 14 | ('v', '5.95') 15 | ]).json() 16 | if 'error' in dec or 'response' not in dec or dec['response'] != 1: 17 | raise TokenException(TokenException.TWOFA_ERR, dec) 18 | -------------------------------------------------------------------------------- /src/vkaudiotoken/ProtobufException.py: -------------------------------------------------------------------------------- 1 | class ProtobufException(Exception): 2 | SYMBOL = 0 3 | NOT_FOUND = 1 4 | 5 | @property 6 | def sym(self): 7 | return self._sym 8 | 9 | @property 10 | def code(self): 11 | return self._code 12 | 13 | def __init__(self, code, sym=None): 14 | self._code = code 15 | self._sym = sym 16 | if code == ProtobufException.SYMBOL: 17 | super(ProtobufException, self).__init__('Unexpected symbol code: {0}. Code: {1}'.format(sym, code)) 18 | elif code == ProtobufException.NOT_FOUND: 19 | super(ProtobufException, self).__init__('Id and token were not found. Code: {0}'.format(code)) 20 | -------------------------------------------------------------------------------- /example/usage/example_kate.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | try: 4 | import vkaudiotoken 5 | except ImportError: 6 | import path_hack 7 | 8 | from vkaudiotoken import supported_clients 9 | import sys 10 | import requests 11 | import json 12 | 13 | token = sys.argv[1] 14 | user_agent = supported_clients.KATE.user_agent 15 | 16 | sess = requests.session() 17 | sess.headers.update({'User-Agent': user_agent}) 18 | 19 | 20 | def prettyprint(result): 21 | print(json.dumps(json.loads(result.content.decode('utf-8')), indent=2)) 22 | 23 | 24 | prettyprint(sess.get( 25 | "https://api.vk.com/method/audio.getById", 26 | params=[('access_token', token), 27 | ('audios', '371745461_456289486,-41489995_202246189'), 28 | ('v', '5.95')] 29 | )) 30 | -------------------------------------------------------------------------------- /src/vkaudiotoken/AndroidCheckin.py: -------------------------------------------------------------------------------- 1 | import zlib 2 | import requests 3 | 4 | 5 | class AndroidCheckin: 6 | def __init__(self, params, proto_helper, str24=None): 7 | self._params = params 8 | self._proto_helper = proto_helper 9 | self._str24 = str24 10 | 11 | def do_checkin(self): 12 | session = requests.Session() 13 | self._params.set_common_gcm(session) 14 | compressobj = zlib.compressobj(6, zlib.DEFLATED, zlib.MAX_WBITS | 16) 15 | data = compressobj.compress(self._proto_helper.get_query_message(self._str24)) + compressobj.flush() 16 | session.headers.update({ 17 | 'Content-Type': 'application/x-protobuffer', 18 | 'Content-Encoding': 'gzip', 19 | 'Content-Length': str(len(data)) 20 | }) 21 | result = session.post("https://android.clients.google.com/checkin", data=data).content 22 | return self._proto_helper.decode_resp_message(result, self._str24 is None) 23 | 24 | -------------------------------------------------------------------------------- /src/vkaudiotoken/MTalkClient.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import ssl 3 | from .MTalkException import MTalkException 4 | 5 | 6 | class MTalkClient: 7 | def __init__(self, auth_data, proto_helper): 8 | self._auth_data = auth_data 9 | self._proto_helper = proto_helper 10 | 11 | def send_request(self): 12 | SUCCESS_RESPONSE_CODE = 3 13 | 14 | context = ssl.create_default_context() 15 | 16 | hostname = "mtalk.google.com" 17 | 18 | sock = socket.create_connection((hostname, 5228)) 19 | try: 20 | with context.wrap_socket(sock, server_hostname=hostname) as ssock: 21 | ssock.write(self._proto_helper.get_mtalk_request(self._auth_data)) 22 | ssock.read(1) 23 | resp_code = int(ssock.read(1)[0]) 24 | if resp_code != SUCCESS_RESPONSE_CODE: 25 | raise MTalkException(MTalkException.WRONG_RESPONSE, resp_code) 26 | except: 27 | pass 28 | finally: 29 | sock.close() 30 | -------------------------------------------------------------------------------- /example/example_microg.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | try: 4 | import vkaudiotoken 5 | except ImportError: 6 | import path_hack 7 | 8 | from vkaudiotoken import CommonParams, SmallProtobufHelper, TokenReceiver, AndroidCheckin, MTalkClient, \ 9 | supported_clients 10 | import sys 11 | 12 | params = CommonParams() 13 | protobuf_helper = SmallProtobufHelper() 14 | 15 | checkin = AndroidCheckin(params, protobuf_helper) 16 | auth_data = checkin.do_checkin() 17 | 18 | mtalkClient = MTalkClient(auth_data, protobuf_helper) 19 | mtalkClient.send_request() 20 | 21 | # This dict element is needed only for MTalk request 22 | del auth_data['id_str'] 23 | 24 | # You can get multiple tokens using this data 25 | print(auth_data) 26 | 27 | login = sys.argv[1] 28 | password = sys.argv[2] 29 | # for 2 factor authentication with sms, or pass GET_CODE to get code 30 | auth_code = sys.argv[3] if len(sys.argv) > 3 else None 31 | receiver = TokenReceiver(login, password, auth_data, params, auth_code) 32 | print(receiver.get_token()) 33 | -------------------------------------------------------------------------------- /example/example_twofahelper.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | try: 4 | import vkaudiotoken 5 | except ImportError: 6 | import path_hack 7 | 8 | from vkaudiotoken import CommonParams, TokenReceiverOfficial, supported_clients, TokenException, TwoFAHelper 9 | import sys 10 | 11 | login = sys.argv[1] 12 | password = sys.argv[2] 13 | # for 2 factor authentication with sms, or pass GET_CODE to get code 14 | auth_code = sys.argv[3] if len(sys.argv) > 3 else None 15 | 16 | # TwoFAHelper also works with TokenReceiver class and Kate User-Agent. See example_microg.py 17 | params = CommonParams(supported_clients.VK_OFFICIAL.user_agent) 18 | receiver = TokenReceiverOfficial(login, password, params, auth_code) 19 | 20 | try: 21 | print(receiver.get_token()['access_token']) 22 | except TokenException as err: 23 | if err.code == TokenException.TWOFA_REQ and 'validation_sid' in err.extra: 24 | TwoFAHelper(params).validate_phone(err.extra['validation_sid']) 25 | print('SMS should be sent') 26 | else: 27 | raise 28 | -------------------------------------------------------------------------------- /src/vkaudiotoken/CommonParams.py: -------------------------------------------------------------------------------- 1 | from .supported_clients import KATE 2 | import random 3 | 4 | 5 | class CommonParams: 6 | def __init__(self, vk_ua=None, gcm_ua=None): 7 | if vk_ua is None: 8 | self._vk_ua = KATE.user_agent 9 | else: 10 | self._vk_ua = vk_ua 11 | 12 | if gcm_ua is None: 13 | self._gcm_ua = 'Android-GCM/1.5 (generic_x86 KK)' 14 | else: 15 | self._gcm_ua = gcm_ua 16 | 17 | def get_two_factor_part(self, code=None): 18 | if code is None: 19 | return [] 20 | return [ 21 | ('2fa_supported', 1), 22 | ('force_sms', 1) 23 | ] + [] if code == 'GET_CODE' else [('code', code)] 24 | 25 | def generate_random_string(self, length, characters): 26 | return ''.join(random.choice(characters) for _ in range(length)) 27 | 28 | def set_common_vk(self, session): 29 | session.headers.update({'User-Agent': self._vk_ua}) 30 | 31 | def set_common_gcm(self, session): 32 | session.headers.update({'User-Agent': self._gcm_ua}) 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 vodka2 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /example/usage/example_vkofficial.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | try: 4 | import vkaudiotoken 5 | except ImportError: 6 | import path_hack 7 | 8 | from vkaudiotoken import supported_clients 9 | import sys 10 | import requests 11 | import json 12 | import re 13 | 14 | token = sys.argv[1] 15 | user_agent = supported_clients.VK_OFFICIAL.user_agent 16 | 17 | sess = requests.session() 18 | sess.headers.update({'User-Agent': user_agent}) 19 | 20 | 21 | def get_mp3_from_m3u8(url): 22 | if 'index.m3u8?' not in url: 23 | return url 24 | if '/audios/' in url: 25 | return re.sub(r'^(.+?)/[^/]+?/audios/([^/]+)/.+$', '\\1/audios/\\2.mp3', url) 26 | else: 27 | return re.sub(r'^(.+?)/(p[0-9]+)/[^/]+?/([^/]+)/.+$', '\\1/\\2/\\3.mp3', url) 28 | 29 | 30 | def prettyprint_mp3(result): 31 | print(re.sub(r'(?<=")https://.+?index.m3u8\?.+?(?=")', lambda m: get_mp3_from_m3u8(m.group(0)), 32 | json.dumps(json.loads(result.content.decode('utf-8')), indent=2))) 33 | 34 | 35 | prettyprint_mp3(sess.post( 36 | "https://api.vk.com/method/audio.getCatalog", 37 | data=[('access_token', token), 38 | ('https', 1), 39 | ('ref', 'search'), 40 | ('extended', 1), 41 | ('lang', 'en'), 42 | ('query', 'Justin Bieber - Baby'), 43 | ('v', '5.116')] 44 | )) 45 | -------------------------------------------------------------------------------- /src/vkaudiotoken/__init__.py: -------------------------------------------------------------------------------- 1 | from .AndroidCheckin import AndroidCheckin 2 | from .CommonParams import CommonParams 3 | from .MTalkClient import MTalkClient 4 | from .MTalkException import MTalkException 5 | from .ProtobufException import ProtobufException 6 | from .SmallProtobufHelper import SmallProtobufHelper 7 | from .TokenException import TokenException 8 | from .TokenReceiver import TokenReceiver 9 | from .TokenReceiverOfficial import TokenReceiverOfficial 10 | from .TwoFAHelper import TwoFAHelper 11 | from .VkClient import VkClient 12 | from . import supported_clients 13 | 14 | 15 | def get_kate_token(login, password, auth_code='GET_CODE', non_refreshed_token=None): 16 | params = CommonParams(supported_clients.KATE.user_agent) 17 | protobuf_helper = SmallProtobufHelper() 18 | 19 | checkin = AndroidCheckin(params, protobuf_helper) 20 | auth_data = checkin.do_checkin() 21 | 22 | mtalkClient = MTalkClient(auth_data, protobuf_helper) 23 | mtalkClient.send_request() 24 | 25 | receiver = TokenReceiver(login, password, auth_data, params, auth_code) 26 | return {'token': receiver.get_token(non_refreshed_token), 'user_agent': supported_clients.KATE.user_agent} 27 | 28 | 29 | def get_vk_official_token(login, password, auth_code='GET_CODE'): 30 | params = CommonParams(supported_clients.VK_OFFICIAL.user_agent) 31 | receiver = TokenReceiverOfficial(login, password, params, auth_code) 32 | 33 | return { 34 | 'token': receiver.get_token()['access_token'], 35 | 'user_agent': supported_clients.VK_OFFICIAL.user_agent 36 | } 37 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from os import path 3 | 4 | from io import open 5 | 6 | here = path.abspath(path.dirname(__file__)) 7 | 8 | with open(path.join(here, 'README.md'), encoding='utf-8') as f: 9 | long_description = f.read() 10 | 11 | setup( 12 | name='vkaudiotoken', 13 | version='0.5.1', 14 | description='Code that obtains VK tokens that work for VK audio API.', 15 | long_description=long_description, 16 | long_description_content_type='text/markdown', 17 | url='https://github.com/vodka2/vkaudiotoken-python', 18 | author='vodka2', 19 | author_email='vodka2vodka@rambler.ru', 20 | classifiers=[ 21 | 'Development Status :: 3 - Alpha', 22 | 'Intended Audience :: Developers', 23 | 'License :: OSI Approved :: MIT License', 24 | 'Programming Language :: Python :: 2', 25 | 'Programming Language :: Python :: 2.7', 26 | 'Programming Language :: Python :: 3', 27 | 'Programming Language :: Python :: 3.5', 28 | 'Programming Language :: Python :: 3.6', 29 | 'Programming Language :: Python :: 3.7', 30 | 'Programming Language :: Python :: 3.8', 31 | ], 32 | keywords='vk vkontakte audio music', 33 | package_dir={'': 'src'}, 34 | packages=find_packages(where='src'), 35 | python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4', 36 | install_requires=['requests'], 37 | project_urls={ 38 | 'Bug Reports': 'https://github.com/vodka2/vkaudiotoken-python/issues', 39 | 'Source': 'https://github.com/vodka2/vkaudiotoken-python', 40 | }, 41 | ) 42 | -------------------------------------------------------------------------------- /src/vkaudiotoken/TokenException.py: -------------------------------------------------------------------------------- 1 | class TokenException(Exception): 2 | REGISTRATION_ERROR = 0 3 | TOKEN_NOT_REFRESHED = 1 4 | TOKEN_NOT_RECEIVED = 2 5 | REQUEST_ERR = 3 6 | TWOFA_REQ = 4 7 | TWOFA_ERR = 5 8 | 9 | @property 10 | def extra(self): 11 | return self._extra 12 | 13 | @property 14 | def code(self): 15 | return self._code 16 | 17 | def __init__(self, code, extra=None): 18 | self._code = code 19 | self._extra = extra 20 | if extra is not None: 21 | extrastr = str(extra) 22 | else: 23 | extrastr = '' 24 | if code == TokenException.REGISTRATION_ERROR: 25 | super(TokenException, self).__init__("Registration error. Code: {0}".format(code)) 26 | elif code == TokenException.TOKEN_NOT_REFRESHED: 27 | super(TokenException, self).__init__("Token was not refreshed, tokens are the same. Code: {0}".format(code)) 28 | elif code == TokenException.TOKEN_NOT_RECEIVED: 29 | super(TokenException, self).__init__( 30 | "Can't obtain token. Code: {0}. Error extra: {1}".format(code, extrastr)) 31 | elif code == TokenException.REQUEST_ERR: 32 | super(TokenException, self).__init__( 33 | "Error when making request. Code: {0}. Error extra: {1}".format(code, extrastr)) 34 | elif code == TokenException.TWOFA_REQ: 35 | super(TokenException, self).__init__( 36 | "Two factor auth is required. Code: {0}. Error extra: {1}".format(code, extrastr)) 37 | elif code == TokenException.TWOFA_ERR: 38 | super(TokenException, self).__init__( 39 | "2FA Error. Code: {0}. Error extra: {1}".format(code, extrastr)) 40 | -------------------------------------------------------------------------------- /src/vkaudiotoken/TokenReceiverOfficial.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from .supported_clients import VK_OFFICIAL 3 | from .TokenException import TokenException 4 | 5 | 6 | class TokenReceiverOfficial: 7 | def __init__(self, login, password, params, auth_code=None, scope='all'): 8 | self._login = login 9 | self._password = password 10 | self._params = params 11 | self._auth_code = auth_code 12 | self._scope = scope 13 | self._client = VK_OFFICIAL 14 | 15 | def get_token(self): 16 | return self._get_non_refreshed() 17 | 18 | def _get_non_refreshed(self): 19 | session = requests.Session() 20 | self._params.set_common_vk(session) 21 | device_id = self._params.generate_random_string(16, '0123456789abcdef') 22 | dec = session.get('https://oauth.vk.com/token', 23 | params=[ 24 | ('grant_type', 'password'), 25 | ('client_id', self._client.client_id), 26 | ('client_secret', self._client.client_secret), 27 | ('username', self._login), 28 | ('password', self._password), 29 | ('v', '5.116'), 30 | ('lang', 'en'), 31 | ('scope', self._scope), 32 | ('device_id', device_id) 33 | ] + self._params.get_two_factor_part(self._auth_code)).json() 34 | 35 | if 'error' in dec and dec['error'] == 'need_validation': 36 | raise TokenException(TokenException.TWOFA_REQ, dec) 37 | if 'user_id' not in dec: 38 | raise TokenException(TokenException.TOKEN_NOT_RECEIVED, dec) 39 | return {'access_token': dec['access_token']} 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vkaudiotoken-python 2 | 3 | Port of [vodka2/vk-audio-token](https://github.com/vodka2/vk-audio-token), originally written in PHP, to Python. This package obtains tokens, that work for VK audio API. Actually there are two versions of the API, one for Kate Mobile, and one for official VK client, each requires a different token. 4 | 5 | `vkaudiotoken` is compatible with Python 2.7 and >=3.5. `requests` package is required. 6 | 7 | ``` 8 | pip install vkaudiotoken 9 | ``` 10 | You can also run examples in the `examples` directory without installing the package 11 | 12 | ## Getting tokens 13 | 14 | The simplest example: 15 | 16 | ```python 17 | from vkaudiotoken import get_kate_token, get_vk_official_token 18 | 19 | login = '+71234567890' # your vk login, e-mail or phone number 20 | password = '12345' # your vk password 21 | 22 | # print tokens and corresponding user-agent headers 23 | print(get_kate_token(login, password)) 24 | print(get_vk_official_token(login, password)) 25 | ``` 26 | 27 | More advanced examples are in the `example` directory. See also examples and README in [vodka2/vk-audio-token](https://github.com/vodka2/vk-audio-token/tree/master/src/examples) repository. 28 | 29 | ## Using tokens 30 | 31 | The simplest example: 32 | 33 | ```python 34 | import requests 35 | 36 | token = '...' 37 | user_agent = '...' 38 | 39 | sess = requests.session() 40 | sess.headers.update({'User-Agent': user_agent}) 41 | 42 | sess.get( 43 | "https://api.vk.com/method/audio.getById", 44 | params=[('access_token', token), 45 | ('audios', '371745461_456289486'), 46 | ('v', '5.95')] 47 | ) 48 | ``` 49 | 50 | See examples in the `example/usage` directory and in [vodka2/vk-audio-token](https://github.com/vodka2/vk-audio-token/tree/master/src/examples/usage). Some VK API documentation, still in progress, is available at [vodka2.github.io/vk-audio-token/](https://vodka2.github.io/vk-audio-token/). 51 | 52 | ## 2FA 53 | 54 | Two factor authorization with SMS is supported, however VK sometimes does not send it. If you don't receive an SMS, you can use `TwoFAHelper` class to force resending. 55 | 56 | It is also possible to create separate passwords in VK account settings and use them instead of your account password. -------------------------------------------------------------------------------- /src/vkaudiotoken/TokenReceiver.py: -------------------------------------------------------------------------------- 1 | from .supported_clients import KATE 2 | from .TokenException import TokenException 3 | import requests 4 | 5 | 6 | class TokenReceiver: 7 | def __init__(self, login, password, auth_data, params, auth_code=None, scope='audio,offline'): 8 | self._params = params 9 | self._login = login 10 | self._password = password 11 | self._auth_code = auth_code 12 | self._auth_data = auth_data 13 | self._scope = scope 14 | self._client = KATE 15 | 16 | def get_token(self, non_refreshed_token=None): 17 | receipt = self._get_receipt() 18 | token = self._get_non_refreshed() if non_refreshed_token is None else non_refreshed_token 19 | return self._refresh_token(token, receipt) 20 | 21 | def _get_receipt(self): 22 | session = requests.Session() 23 | self._params.set_common_gcm(session) 24 | session.headers.update({ 25 | 'Authorization': 'AidLogin ' + self._auth_data['id'] + ':' + self._auth_data['token'] 26 | }) 27 | data = { 28 | "X-scope": "GCM", 29 | "X-osv": "23", 30 | "X-subtype": "54740537194", 31 | "X-app_ver": "460", 32 | "X-kid": "|ID|1|", 33 | "X-appid": self._params.generate_random_string( 34 | 11, 35 | '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-'), 36 | "X-gmsv": "200313005", 37 | "X-cliv": "iid-12211000", 38 | "X-app_ver_name": "56 lite", 39 | "X-X-kid": "|ID|1|", 40 | "X-subscription": "54740537194", 41 | "X-X-subscription": "54740537194", 42 | "X-X-subtype": "54740537194", 43 | "app": "com.perm.kate_new_6", 44 | "sender": "54740537194", 45 | "device": self._auth_data['id'], 46 | "cert": "966882ba564c2619d55d0a9afd4327a38c327456", 47 | "app_ver": "460", 48 | "info": "U_ojcf1ahbQaUO6eTSP7b7WomakK_hY", 49 | "gcm_ver": "200313005", 50 | "plat": "0", 51 | "target_ver": "28" 52 | } 53 | result = session.post('https://android.clients.google.com/c2dm/register3', data=data).content.decode('ascii') 54 | receipt = result.split('|ID|1|:')[1] 55 | if receipt == 'PHONE_REGISTRATION_ERROR': 56 | raise TokenException(TokenException.REGISTRATION_ERROR, result) 57 | return receipt 58 | 59 | def _get_non_refreshed(self): 60 | session = requests.Session() 61 | self._params.set_common_vk(session) 62 | dec = session.get('https://oauth.vk.com/token', 63 | params=[ 64 | ('grant_type', 'password'), 65 | ('client_id', self._client.client_id), 66 | ('client_secret', self._client.client_secret), 67 | ('username', self._login), 68 | ('password', self._password), 69 | ('v', '5.95'), 70 | ('lang', 'en'), 71 | ('scope', self._scope) 72 | ] + self._params.get_two_factor_part(self._auth_code)).json() 73 | if 'error' in dec and dec['error'] == 'need_validation': 74 | raise TokenException(TokenException.TWOFA_REQ, dec) 75 | if 'user_id' not in dec: 76 | raise TokenException(TokenException.TOKEN_NOT_RECEIVED, dec) 77 | return dec['access_token'] 78 | 79 | def _refresh_token(self, token, receipt): 80 | session = requests.Session() 81 | self._params.set_common_vk(session) 82 | dec = session.get('https://api.vk.com/method/auth.refreshToken', 83 | params=[ 84 | ('access_token', token), 85 | ('receipt', receipt), 86 | ('v', '5.95') 87 | ]).json() 88 | new_token = dec['response']['token'] 89 | if new_token == token: 90 | raise TokenException(TokenException.TOKEN_NOT_REFRESHED) 91 | 92 | return new_token 93 | -------------------------------------------------------------------------------- /src/vkaudiotoken/SmallProtobufHelper.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import binascii 3 | import sys 4 | from .ProtobufException import ProtobufException 5 | 6 | 7 | class SmallProtobufHelper: 8 | def _write_varint(self, num): 9 | data = b'' 10 | while num != 0: 11 | t = num & 0x7F 12 | num >>= 7 13 | if num != 0: 14 | data += struct.pack('B', t | 0x80) 15 | else: 16 | data += struct.pack('B', t) 17 | return data 18 | 19 | def get_query_message(self, str24=None): 20 | if str24 is not None: 21 | resstr = b'\x10\x00\x1a\x2a\x31\x2d\x64\x61\x33\x39\x61\x33\x65\x65\x35\x65\x36\x62\x34\x62\x30\x64\x33' \ 22 | b'\x32\x35\x35\x62\x66\x65\x66\x39\x35\x36\x30\x31\x38\x39\x30\x61\x66\x64\x38\x30\x37\x30\x39' \ 23 | b'\x22\xe3\x01\x0a\xbf\x01\x0a\x45\x67\x65\x6e\x65\x72\x69\x63\x5f\x78\x38\x36\x2f\x67\x6f\x6f' \ 24 | b'\x67\x6c\x65\x5f\x73\x64\x6b\x5f\x78\x38\x36\x2f\x67\x65\x6e\x65\x72\x69\x63\x5f\x78\x38\x36' \ 25 | b'\x3a\x34\x2e\x34\x2e\x32\x2f\x4b\x4b\x2f\x33\x30\x37\x39\x31\x38\x33\x3a\x65\x6e\x67\x2f\x74' \ 26 | b'\x65\x73\x74\x2d\x6b\x65\x79\x73\x12\x06\x72\x61\x6e\x63\x68\x75\x1a\x0b\x67\x65\x6e\x65\x72' \ 27 | b'\x69\x63\x5f\x78\x38\x36\x2a\x07\x75\x6e\x6b\x6e\x6f\x77\x6e\x32\x0e\x61\x6e\x64\x72\x6f\x69' \ 28 | b'\x64\x2d\x67\x6f\x6f\x67\x6c\x65\x40\x85\xb5\x86\x06\x4a\x0b\x67\x65\x6e\x65\x72\x69\x63\x5f' \ 29 | b'\x78\x38\x36\x50\x13\x5a\x19\x41\x6e\x64\x72\x6f\x69\x64\x20\x53\x44\x4b\x20\x62\x75\x69\x6c' \ 30 | b'\x74\x20\x66\x6f\x72\x20\x78\x38\x36\x62\x07\x75\x6e\x6b\x6e\x6f\x77\x6e\x6a\x0e\x67\x6f\x6f' \ 31 | b'\x67\x6c\x65\x5f\x73\x64\x6b\x5f\x78\x38\x36\x70\x00\x10\x00\x32\x06\x33\x31\x30\x32\x36\x30' \ 32 | b'\x3a\x06\x33\x31\x30\x32\x36\x30\x42\x0b\x6d\x6f\x62\x69\x6c\x65\x3a\x4c\x54\x45\x3a\x48\x00' \ 33 | b'\x32\x05\x65\x6e\x5f\x55\x53\x38\xf0\xb4\xdf\xa6\xb9\x9a\xb8\x83\x8e\x01\x52\x0f\x33\x35\x38' \ 34 | b'\x32\x34\x30\x30\x35\x31\x31\x31\x31\x31\x31\x30\x5a\x00\x62\x10\x41\x6d\x65\x72\x69\x63\x61' \ 35 | b'\x2f\x4e\x65\x77\x5f\x59\x6f\x72\x6b\x70\x03\x7a\x1c\x37\x31\x51\x36\x52\x6e\x32\x44\x44\x5a' \ 36 | b'\x6c\x31\x7a\x50\x44\x56\x61\x61\x65\x45\x48\x49\x74\x64\x2b\x59\x67\x3d\xa0\x01\x00\xb0\x01' \ 37 | b'\x00\xc2\x01' + self._write_varint(len(str24)) + str24 38 | else: 39 | resstr = \ 40 | b'\x10\x00\x1a\x2a\x31\x2d\x39\x32\x39\x61\x30\x64\x63\x61\x30\x65\x65\x65\x35\x35\x35\x31\x33\x32' \ 41 | b'\x38\x30\x31\x37\x31\x61\x38\x35\x38\x35\x64\x61\x37\x64\x63\x64\x33\x37\x30\x30\x66\x38\x22\xe3' \ 42 | b'\x01\x0a\xbf\x01\x0a\x45\x67\x65\x6e\x65\x72\x69\x63\x5f\x78\x38\x36\x2f\x67\x6f\x6f\x67\x6c\x65' \ 43 | b'\x5f\x73\x64\x6b\x5f\x78\x38\x36\x2f\x67\x65\x6e\x65\x72\x69\x63\x5f\x78\x38\x36\x3a\x34\x2e\x34' \ 44 | b'\x2e\x32\x2f\x4b\x4b\x2f\x33\x30\x37\x39\x31\x38\x33\x3a\x65\x6e\x67\x2f\x74\x65\x73\x74\x2d\x6b' \ 45 | b'\x65\x79\x73\x12\x06\x72\x61\x6e\x63\x68\x75\x1a\x0b\x67\x65\x6e\x65\x72\x69\x63\x5f\x78\x38\x36' \ 46 | b'\x2a\x07\x75\x6e\x6b\x6e\x6f\x77\x6e\x32\x0e\x61\x6e\x64\x72\x6f\x69\x64\x2d\x67\x6f\x6f\x67\x6c' \ 47 | b'\x65\x40\x85\xb5\x86\x06\x4a\x0b\x67\x65\x6e\x65\x72\x69\x63\x5f\x78\x38\x36\x50\x13\x5a\x19\x41' \ 48 | b'\x6e\x64\x72\x6f\x69\x64\x20\x53\x44\x4b\x20\x62\x75\x69\x6c\x74\x20\x66\x6f\x72\x20\x78\x38\x36' \ 49 | b'\x62\x07\x75\x6e\x6b\x6e\x6f\x77\x6e\x6a\x0e\x67\x6f\x6f\x67\x6c\x65\x5f\x73\x64\x6b\x5f\x78\x38' \ 50 | b'\x36\x70\x00\x10\x00\x32\x06\x33\x31\x30\x32\x36\x30\x3a\x06\x33\x31\x30\x32\x36\x30\x42\x0b\x6d' \ 51 | b'\x6f\x62\x69\x6c\x65\x3a\x4c\x54\x45\x3a\x48\x00\x32\x05\x65\x6e\x5f\x55\x53\x38\xf0\xb4\xdf\xa6' \ 52 | b'\xb9\x9a\xb8\x83\x8e\x01\x52\x0f\x33\x35\x38\x32\x34\x30\x30\x35\x31\x31\x31\x31\x31\x31\x30\x5a' \ 53 | b'\x00\x62\x10\x41\x6d\x65\x72\x69\x63\x61\x2f\x4e\x65\x77\x5f\x59\x6f\x72\x6b\x70\x03\x7a\x1c\x37' \ 54 | b'\x31\x51\x36\x52\x6e\x32\x44\x44\x5a\x6c\x31\x7a\x50\x44\x56\x61\x61\x65\x45\x48\x49\x74\x64\x2b' \ 55 | b'\x59\x67\x3d\xa0\x01\x00\xb0\x01\x00' 56 | return resstr 57 | 58 | def get_mtalk_request(self, auth_data): 59 | id_bytes = auth_data['id'].encode('ascii') 60 | token_bytes = auth_data['token'].encode('ascii') 61 | id_len = self._write_varint(len(id_bytes)) 62 | token_len = self._write_varint(len(token_bytes)) 63 | hex_id = b'android-' + binascii.hexlify(auth_data['id_str']) 64 | hex_id_len = self._write_varint(len(hex_id)) 65 | msg = b"\x0a\x0a\x61\x6e\x64\x72\x6f\x69\x64\x2d\x31\x39\x12\x0f\x6d\x63\x73\x2e\x61\x6e\x64\x72\x6f\x69\x64" \ 66 | b"\x2e\x63\x6f\x6d\x1a" + id_len + id_bytes + b"\x22" + id_len + id_bytes + b"\x2a" + \ 67 | token_len + token_bytes + b"\x32" + hex_id_len + hex_id + \ 68 | b"\x42\x0b\x0a\x06\x6e\x65\x77\x5f\x76\x63\x12\x01\x31\x60\x00\x70\x01\x80\x01\x02\x88\x01\x01" 69 | length = self._write_varint(len(msg)) 70 | return b'\x29\x02' + length + msg 71 | 72 | def decode_resp_message(self, msg, need_id_str): 73 | return self._find_vals(msg, need_id_str) 74 | 75 | def _read_varint(self, data): 76 | i = 0 77 | num = 0 78 | length = len(data) 79 | while True: 80 | if i == length: 81 | raise ProtobufException(ProtobufException.NOT_FOUND) 82 | if sys.version_info.major == 2: 83 | tmp_byte = struct.unpack('B', data[i])[0] 84 | else: 85 | tmp_byte = data[i] 86 | if tmp_byte & 0x80 != 0: 87 | num = num | ((tmp_byte ^ 0x80) << 7 * i) 88 | i += 1 89 | else: 90 | num = num | (tmp_byte << 7 * i) 91 | break 92 | 93 | del data[:i + 1] 94 | return num 95 | 96 | def _read64(self, data): 97 | if len(data) < 8: 98 | raise ProtobufException(ProtobufException.NOT_FOUND) 99 | res = str(struct.unpack('> 3} 106 | 107 | def _find_vals(self, fdata_bytes, need_id_str): 108 | ID_NUM = 7 109 | TOKEN_NUM = 8 110 | id_found = False 111 | token_found = False 112 | fdata = list(fdata_bytes) 113 | while True: 114 | if len(fdata) == 0: 115 | raise ProtobufException(ProtobufException.NOT_FOUND) 116 | fwt = self._read_field_wtype(fdata) 117 | if fwt['wtype'] == 0: 118 | self._read_varint(fdata) 119 | elif fwt['wtype'] == 1: 120 | if fwt['field_num'] == ID_NUM: 121 | id_found = True 122 | if need_id_str: 123 | id_str = bytes(fdata[:8]) 124 | gms_id = self._read64(fdata) 125 | elif fwt['field_num'] == TOKEN_NUM: 126 | token_found = True 127 | token = self._read64(fdata) 128 | else: 129 | del fdata[:8] 130 | 131 | if token_found and id_found: 132 | res = {'id': gms_id, 'token': token} 133 | if need_id_str: 134 | res['id_str'] = id_str 135 | return res 136 | elif fwt['wtype'] == 2: 137 | length = self._read_varint(fdata) 138 | del fdata[:length] 139 | else: 140 | raise ProtobufException(ProtobufException.SYMBOL, fwt['wtype']) 141 | -------------------------------------------------------------------------------- /example/example_droidguard_str.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | try: 4 | import vkaudiotoken 5 | except ImportError: 6 | import path_hack 7 | 8 | from vkaudiotoken import CommonParams, SmallProtobufHelper, TokenReceiver, AndroidCheckin, MTalkClient, \ 9 | supported_clients 10 | import sys 11 | 12 | # Example of droidguard string 13 | str24 = \ 14 | b'CgbC-r9OsTzaB7kDAOuhCBLyM6BOvSP-vbtLANoV6FJa8qAPyyWnIM0aO1_guBvVA5dWr7aUrqtt6-2XKaWJt3vAEA3qCrMUMmSNb' 15 | b'4kdWWrA6PldlN0BJolfQuHJ2jIqD-gcKsw1OwmmCbi3kgi6FD5pV28jYIibkVL1HIC9AneVx1Z2EaPTLCS5sOy9dByVKXggmXn6ob' 16 | b'XeQlefiQjNomuGmdouNRY1inOlRLAa0tvAD58DCbeHxBmbVx-vRna_2Gv9upxeDhDz23XvzJhjf6PyLt49id13RZm7Sd4xNZc-fIb' 17 | b'3k2hSIW-u7IlJc-qVng3fL72EsHgSeni5StSpWg7jg1Dl6lJCrZdyOxywCb7whDhCi0yTq5rjLLK6KVaqhsI0u2-KlHt3Kv-H0k7b' 18 | b'SARSq-G6qrXEh5vSA1xaDfKDQ2o3S9adFUH5Hg8vhseYyK77ZQymTlPCz8zl_skdZn3pcXWMfp4H9-w-1B4QxWDluW8yazZPDPbfb' 19 | b'XRSqO-DYSZ-ZxLre71hYWrp-DEkCTr-UDafLYbVPqtRVhEJ1FuX-4cO6OxpwaGbBF1ZrsFWGhEIeEkA3u9fv8XoJMoFFRS2ISOB_b' 20 | b'o5qnOGEaDAjb_YX_BRDjlunGB-gB6dWx-_r_____AegB3vGZwQI4azhLEqQ_22tkk57EEcp4JhiF_qRPQR4ra7NKxe6ALEs-9QMNb' 21 | b'qa74VCMXCtbu7RXS234YJoX5S4V-Wlx1qGmkPP8dOm225mELt9plHw00PEGPMwJQ2_hY0nI7GqyEgRLzwuGhFe1T7J_qtVCKzkR3b' 22 | b'eRNhU3p8XEa46oy0IXJK9po2Vqg_i9GM7EuZOLV_Gop77Ify9VOeCH9rHVyk7FR7DYpoa1bSbTTeZuEHo2wh3JDvt95r7l-mG7XPb' 23 | b'UK3GupSpDKoFKNoY9xjrpjv2FDJcjvfVtptzCUs3TU9E25t6mO0a2EPG9k0j4mIWK8li1mzYJIcd3Bj4obMN2jIyELSvYFREPcyNb' 24 | b'jO8xK_7HX0Wt6eeacg3rzlFOHePjsMHwQN1u8zJSd4xV47omhy3mv_AJEJG91MpVySNAJ2w_R4H660IXWt1pe0Dl8kdEA-8mjBdyb' 25 | b'-GaijIKU8c67IUQrTIHo5QvrZEcI_cGI5Xyoo1N3-g_AoKG5l7Wnc6hyCbK5rz1bHE2MgXJGDYUjgZNG6lDAXUvoj1hHYal-tVSab' 26 | b'L6pvOpigClzFS9Tbt9q_URP-f-t4jbI6O89ezFtOkeXpUD_zxwqazoqZaZTI0IEoiv0d9s1KnZ510PJ5TXOMiOiemuc1qV0XeH5Kb' 27 | b'GtwwyI66o0yLG5I_8qQzGuiJBv2lPa-GkI3_0efx1XKIT9ItzMBcPoWkf8FL1EvwA-dzpFy969SPPKk5Ubt1Bo6kkbzLLTsHmeHGb' 28 | b'VPWGfIBVNxuE5XMDdc3NuFnbysdfkixGFUnWYAl9p4xgDUxE4XPEC9WYds66KmSjoqm7JlgBL7R_tYcE8g_7V1d2e4urccUJeC8Ub' 29 | b'BhqMQAcU2Idfhzd9cZTjjMKotc9cudd8zWB3kmGeARm7wE_fs8F1gZXBrefc9ZCVHBkD5ttp3LS519jGuN1uH8CyNkcPOLhelLITb' 30 | b'_fsmBWXAWa-c1LxCWB-QVJfGZhcESdxqw8ZIWTo_WM6pjn7rjyfEe7ukdaUE6gvEXRmhSHYrKEGNFfImjQW7QS9AKc6hRi-ZTH3eb' 31 | b'Q_V_NVahA-PVYp6n7k3iqicSCCo8rviQsA-VnZegzkWkVjqxts-N77qsnUHmjfxd9wflNxVrMi4ffADJHc7DPboeDTFegJlKiGcNb' 32 | b'EQbuuvbFBWsI1IFwO0y4CHCm-vTmwetPrAKhkIjFZGGRRt6X8686cHkWo9yU4PQ_WY4-IgM1SC_JFATtr2q23auVHFUpCB8ODphBb' 33 | b'grCQYAIRIdxR6TQhpGJE0UUouP-kTBOEVnHjPpcCSR6EDLqms_4DDzgSJw9cS7x6i73jijvmObjHh08JV4k52vxprXA_2OJbp8aeb' 34 | b'tqTrHOsyJcRDQ0nI9DB_apk2G9tkqp6M_lS-x0IuYbhRisQKO3Jtz6p5tb3CEsjtapBXmctgo7mM2HvKRJmsj_6xnTZT_TXAsFrHb' 35 | b'K65-cixhFwE4vr79sRt7HUYDBiXehJDHoaSVBEQ30GUfAbxSSDH2H4fJswOCJl2A6MZ3vCdyspI2mWVr5HnJCWVZDqhQPZVVDEDQb' 36 | b'mCfhE3AAZzEaDoAzs4v9WKSfOWQr7KVebwRghmFTCnZifiKPqtxHJd1YyS0QRkNRLkbmYIPG8BieTxoidHO3X_jl4s1_fuqRWjQWb' 37 | b'E6uYEfKwlcR9SxMfrNDiLVtiKvkGM0MdrPDrrsk1xRWYe5_Jh0AyZOkfjlC_HgEtwuhlkGcGAux1e3kSBOqkfJLZiHkKiA42iSnZb' 38 | b'i68N9KRMhbmmG6jIc_rAiT_KQIPisFO1RbWDGy09yWAwTqLOzkmFaxNgX3WZJZwX0oDRYC4Ooczfp-wo3mp6jlyZklEMKenRYdNDb' 39 | b'ThSQROiVSLNaYYfxsEl3ZAyJT0HZbDyuJRcoOTSiOEWLgqIQnkF2ww1xj9oIW-49vGnp_oU6uVHSP-gVym2MHNhowivrDiKkGQcBb' 40 | b'C5bAq9zbaVvbS5zTjAgQRlfJN4TLaXaLD2GqhrDyfFEl8yGnaGnkS5mzHwumrdOzqDsaAx8I-2DhaUbWAfk3K1INGmEuxdhh0z-Sb' 41 | b'jhCJOcyLHf0bJ32QzqAjWiafc_BgbpqZokgGrz04nZYrf1MfeO6TsxTm2KkQhdBchwMNYFPDsZt-y8wYANAQhrNW-R9Skq5Qlqnxb' 42 | b'LMtAKO0xPafa5hWBRve7n8N3lg0n_d-tqW2xIE6mbn5kmmJgFZjaK8uhDodWYQAW7Nnvh-YR8bLHiZ9uHX6EqxtXq9DRLwXVGtxvb' 43 | b'UfHX3jMNQ8ERMc_98I-hS0lU166Q249IT64gF94cTu2nZWMcO5G1XlfoauYp-OVbqtYmt28_1o33uAo-bPkEFIvDRdsSzxP5-3Mqb' 44 | b'sq_8bh1kMIxGAw_0f8CvxQ3p8TvMaWkJ90itnZexd1d0U_UkRbSX3whu2-D0e4vY4rJpcrgOAyd4R8lDpJsyqsOchqrX7TcGgeMsb' 45 | b'yRDbBoEESfTRCbEkb95m_Z61tojO1oUOv3nn1ryXtyRLPeZrXuc3MimUbNaH8mlCh961CroIS-uS-AAp3nd6RHiSr15aZCDMXvtNb' 46 | b'Qej2qhtFeSCxDdKI5PDkB85JbmKyyWElkj5cJbCxA9YLNt8oGYFUFuGih7bU4pz2PWlXwRbW1Y6Y7RuH9osjzQvVsffIYIRimNb9b' 47 | b'bvmX3t1OuHG45Kr6H_x6bZ3rX8n1AgJt3qnA1WAPaG_k_QzNyILOFnFJ-mZQFYTft8_2xGJOjR_WrLUvq6IrPNNxHmsDwjHrPqu1b' 48 | b'acSGaZYSSUDyxZGQbZUlv0EHlmtAezwlMQlgoNP2ji7ig3o7NNYjf5pEY4M5KefPEqxshRA2CfIkZJqEFoykHlzY7-8Lwg3Yrd58b' 49 | b'Di9BzvzgJVm3i16mQ-YwVj2VYyhmnsrAXzUX4mC3MVXsf1O4j7HANcYBS96M4-sB2_W0N1qCatNMK-AMpNGn3fnXJN3KoRJvWcSLb' 50 | b'_54j0GU8akky6G6pl0a_LQM1s1edOcKkr_2o4YoOK803nwfGwv5UN9Oq5xHIZZzq3UcewXYHghYVLqYQYsyRBwzNycwPz4aAcmEpb' 51 | b'at6clxSR-H5PN_Tgkvc86vV2yAHC-9MquXYtG21ZSVQFg3OlK-jpNAD1mzdwGLOSL6KWAt-gqDhnjURvaUpGMTbX-DruXglFdJmab' 52 | b'_SntniSCWzFhJa75GZjHEBcXe5Rzns87RCOzVyu8rTfbxu-HhGok49-1dn_AGGwUYDU1vEQt27VsCetOYTujuUUH9DXONhCSirXbb' 53 | b'ftR3uZ57ZHeQ5ls49-GhxgRp66q3yaqMrPce_jXdZmSA2cEuvYaSRWXrK8u3wAS-3V_7y0LzKvy_t62lB_s4n6-2ywlp_qHo91Ofb' 54 | b'wDWSNM8JbnBIU_ao50KrIHzNOASQJL3SIwIgwrXqXEq58-5DrDxyNiypSW66GgearcY0S4qAue1Y81LgFe2-4SIeiVXGILkl0OlJb' 55 | b'q_E7LEjcXY3IlfjfBuvFJKpqCtRuVbvPreuKTKCvmW97ybhsxXGOlyeTeY4OReQWax8jx09fzGjRvK0I9fkJMNP0DoPcPjIxicVYb' 56 | b'Kh3j6sy9qGFAdnJ19MuxODeH6IrpueLFbaggd7RbR3y1OwYZDnJ1F8O4bE-mSF5uqlOk9nXGAevxGdHkR5bPUbwMmg4eWq8i6q9ab' 57 | b'pWD3oJefQg1Td0gIab5gL0HS-CSvNLWbfxgJ2w-OavzEozsAi6tkMDcfeKcErUFyigPV8yOO-g1j8sq0jOV6XOWqHtcDF5pHGArxb' 58 | b'4A01blK0ndsmmpFwbBhtwujRTCXfiQTmRAs2TmZCCvo-LzuvGD9pmUYGMg9QHeQC7YutIJ7AbEvceLLKng_7OabzROJ3z-yNar8ob' 59 | b'sKzlAxAt-mOFrZ7diwPIN_iGeonr87bvzHdPsUGlw8TJQZPOIV32elicvKb9f_PE_XdqgLlZ5urua7ZdBP7kTK4oQPY8Y55GFW-vb' 60 | b'3dN4O7g98TrKPKjWI_W9AQ34JXJ4ulJdMgqz7YKft_OCHyc0vf796DAnY31e2-_CL3Le9xBxXBC1Q4xzaz-igvsAWbGL3eCJ8NZ6b' 61 | b'LXcFrRV6KAdjEUOfY_cp_b2Ghv1H6PijoVKCEWV_tw6Y2UJsxj6jmMW35n6WqMy_asVgYCJ6eLkstitlncZ9UvBplAQ6TlSIRslkb' 62 | b'4RXb-Cs8wzk-JJOrHOHyriueQ9PPLOuCiiNFvRU4XvWwZuhv-dE206vv9UAxiCVRZhX7AOlAktsshDIqH3PogMPPTXg_mfvhUFVPb' 63 | b'5yixFTP3eTcoLW48SENDuieH_s6BDzVv5U40p05ng0iDOHP4SvhGFl_J0AoJv8Dx8yhdQv6XfDptELOunXGN8UANjta-S9R2RGs2b' 64 | b'j2LLUxLsHCp5Aq22E2LFhikeTkE8ckxiW84NAtK2fCYZSyOWqX7ANDi0Ndq0GcOOkIkpsd6Y9_vtyVMuPwWC1lJlGhESsKr8U15zb' 65 | b'PoIazDHwPXkkP3i6cT23pIfuliTndzz7T31o-AxdD_1vJjpf1adqs8GoZZrhoq1NR62mNek40Skszm58Zi0Au1IQ__A3Qelv40bUb' 66 | b'FdnzP7Zi9JeVIJy4U-wPG3u2AXM51hyJVDOt2rYE0Tkn_VqyvFi-qMsCa1x6BmauxENxU0E119iw8R_bvjS0fwgngCONkOQE2acKb' 67 | b'P1aliLzppIU4cwiWBXC2uKtcgM8N01RRQ8s8ovIa92VMtwoylKbi90jkHiqJL4UYsgpgv-566Gj5EnFQ8Y1as7hSSwYrYz3DJgDPb' 68 | b'lz1p6crHMdOAmB666mcD3BJNm3TJBsjc6xBViQWvdnNNrR92zQryIrujp-jEIGpsTNQXMpb9PELonzzyLnNBHyXAdHeQzD0KluDxb' 69 | b'InQInA8StYnLTLdt0nKm8mOvqvR8z7ftXOPhmsx_IzBJuSzjQdKav0DgfmRRTxWvBm7n1ORHOmBipXEqmxELwesK3ValjP95h3yqb' 70 | b'peaadHdY_KzIq8IeDO0s1nJKHFHm75oneMr5QDGwHDNxESi44upFMv_z6zRWsTkICFLmAcL4gFMZ3j8X5yY3cFD_yv6l0xbvyjLBb' 71 | b'GySbH7199BKlPB_SrXuDU1-InWKW3dAY8R0SOeRaIivbkPVQSnrs6FO8Atp6koVUaDEvSTz5ZiarnpJSpyszfCfCvU1q3SeDkq6vb' 72 | b'YtjRKnBTo-mQsmR9tv-50vxAaDDWY1XQ10l-pdWu4YTAvmd6rYHJHQ_fCsMmDWT6PiAU0YxsFbpb1rfaAPj-T93MpulIVbEEQIznb' 73 | b'O1ns8begjyCzbfa6eBMGMnl2lvMz_qbsJLKEdlbTOFu3wkPL7Iit9icnGF7mTcRGqs5fgCvw_Ggg-OKCGZSyNJwpNqto1iVYCcTUb' 74 | b'qgIM4YLEfBy5A_y1FN5wfLpYII5FaeXHcj9mYLjL8kPEcrRScuaJ4JOQvw99gSOh_n-AeIaiyfIZcC7rW2E4-gDq9idSg5aIxagJb' 75 | b'WW3kH0droQhOB3NhcEh8wegWiQtKPs9xtTx18kZv44gNVAHVw3yYeUW6tItyuCDct51GDF3Q9ow53oHDD4SWH5OQdT-vVDZvm_MKb' 76 | b'0KaR6QVXUQ33nLkAFtIygPsdRBZDewDxgTdZL7PArEd3TJFwxdtPa07_ymh_id6-Qe1hC_Th_mGxI6zVS24_Al-e3ApTHPYi8Glvb' 77 | b'8CevLDz079Hf-OTK4HTFH5hRe1bxEs9CoHnBztTKjshp8jPFuSXBTGU05cPdr80IsvyfYEo_uW8W2Duhd6pVjJ8RKvrbj8XMV2Iwb' 78 | b'Y2GLrux5kHDQvGYTKNBSm8WGAwIfaFEYU5HVeQT9vO4JEajN3vV38HKG48__4Gko1YRxjSUEZzx0dM82SB959mN5tBA4Pq_a9eynb' 79 | b'xWN19KINg-25TL4xNMqiqRAfrQGsjiTBC7UL-K2Gmj0MYSBTVtCNdrUwPGrTxKKHFTqaS5JQgzXLM2cvdDODMgrKG-IZ5MTrbmTdb' 80 | b'uNYRcPPNoW04MGm6GDiRg_lK31bYeCa-2VJ2hmCnTWyyXqFsS0ALMj7uwvDj63fWDIdDhh1efHUNzt5HhYmJeBG0Tpwqy5RQPirBb' 81 | b'ZM0mKyRDO4IfmVH8heisqWtx1QI4Eskb_Tp3KLuUG07OztoBYUDfltecfWniXx5LDX6qlvIi4KUM9vT1CFlsPUUnN3t2vPYfi_N_b' 82 | b'rmHEsyydLZThuuSurcxcynwCFTqAr5UKSMJG9bununGamIuIczFknjLCmMg9A2PgZsAehcv3DZpZoVErflKDF_D1qbGBGNJdz4W-b' 83 | b'TqhJShjHuSHaWdwUQzInAwfs634vNQYbMTJW-e72nQJTBFXoLs0Vm427aWbHU1GmUCt5m69AxdYTEObBB1T8yaeVBKA_Mnv7BdqKb' 84 | b'4VSnrklqLVQXbEguKnegNsR5FLGnESvuGCpnXL-mDIuQIEktrUkKxqueWbdT_-AREiiL1dwMSTtT-jw-0Mifoxw2X6T-frm6uZxRb' 85 | b'rpMLYFqclaO1MP4B6sESsFGkCygwzUj8wCXtdk4jZtvk9MQAyXI61vRMOuWqAILiN2p04pjE2xpbxt_uBTjZEEEW56wUQdhSrkPhb' 86 | b'Gw7B6uIRUEcetzX9C9tz_z3iQfrFj4pnLylIGbSuRJQdnj4oeODzEcwLspApgVtAaZveIrtWoKa1N2lDAqO5C_tHXnGbJlrYC2SSb' 87 | b'D9LoS-Uz4hc_009JLJY4KZlfwQ07fdt5U02ofeboMOI8tNpg9erlUn-GaEJQTll4Konu_aS-C4MmJzxlWOsbef9Wr9V2MqNOKSjGb' 88 | b'caEIarh86LJq_5EcGfhPqh-kbNynqiiTS6ZrF8Uq4OdvIULG7M4CKCWYSsBZjeQZICWKaraFSDv85wuX5_eogsIcuUFBS8jJXgR3b' 89 | b'Bst9fOUicu3kZ41rksXBjdqPkh1yy0XeJO-CU-FDwzjWmRDpaayLizzr9Vs4pAAJ9mOVHTEqzQMogZ-I6EZjgGbeSlC9WDcHBbpob' 90 | b'7YwCuTz74KY7C_ZlgWU7Lp1Kn1P1ApPbRgS0vMiPBMwzgsWwOx6Pfo-Fe9JTZxGZx7sJxxcOACefgcJ2oJ5atJxDRYqZ8QYUZWyEb' 91 | b'6QKHyxs9Vj4HtP6gPy6V7_6nulK-JX0pp__qeqESGtscFYupxyzCBP_ygdLsmaeFlPFnKjLDl9psKf34KKl1GcRLW3Bk4LezAd5Hb' 92 | b'WzQ4pfQNOFA-O7Q0aRJrgHM8QMbn5DMAAk-95JWNxj7ETHGY0Y4RXymicDHv-ikVtBst9A10_Ps33-N0rQ_L5Jvb43t5I34kpbWtb' 93 | b'D3YsSwfPfxxwZ-2uPQdCZMYxkk1-90gfGqkVkJ0ilRKL5nH7Dj45dwRA3F8wRsTVQ_HT2eYsc8D0FpoZJBsgol8okH02yYv0BoDab' 94 | b'qCn6JuQ-hD0hdCy3Z_I7cMo_cLmSHGfRqbIQeKIbJIc9OLthW2UcTYrf-Y-_vYdnnSKOcI8ItgF-GIAyoBELAIXRrHLKR3QlabFGb' 95 | b'gEhC90MY83DIytcqlIG2HJ_mBIXiWhFQCJDSzNXxW9Td_OELJaaXGQJqP1YO_C89LYOAstsLOoYPDvpzdMFMPA-84cNVW5heIALHb' 96 | b'xAingTXU5K0L1EQPOBqkyFZSe1CdBHOgt1945d-3tFTKZacpKh1jb4Wh_QxcaneNOKCQCyapR_muVJjufJ5SECPwAwoRFvAaK5isb' 97 | b'R43_8OaS3947ZS2GOazgvxyECciWu-OvQPL1llSAGIrskaGLQab0KSR2dVvf5uHmgNon5XpTtW1o1JA_GfWvOCXfCmSP4IxAYNrNb' 98 | b'TtqAUPOOJMdu_iaqFg-VEwzcw3TCNW4xurydwQx3dCbxWjqM07tHmHMUijceh7cQdTZTc7diiBkETZNstlgJuFZmL1FVovMcSc4Ab' 99 | b'0y1ogZNRB1ATjH3ONHkD93m_RtaDX115onkYz7vBfZVeOFjjDumwxaI9dGb0GbKsaqOnW9LVG1G0oiwfvkfeO0_c3TZvgYHjpw3fb' 100 | b'vkV-aL66uvYNjO6lF83-zPI2c69_x0tXxYRpKNMBUGPGLeRterrCTYYPLi8pTXiVDGEHKuAfiF6JN76BQkxO9PVki0BcJAmJctnmb' 101 | b'QMT21FU9uL_XQQ-rHmVHXeeSGJpLtnUywc6Knhw-fRHIwHGTFFZW1a5Z3ijS-k38AStydxOljMcP5xxXjbJXLbVHdrCaQPF5E-4sb' 102 | b'wNOSh1SWuiSngpyUhFt3oXJxtfDzkp-8y0pimPWPJHeHXiTJdI6gZ6u9Yl2P7cA0KEmEDDcbj2ZtToSwrjxAaOeocZTpIxRJ_JU_b' 103 | b'N7Hhd7K4n6Dy_sxRKhMJROVuR9AVt_4MYU1OlhOzFfj6xq6sEUZ9J_B7grmjNjXge3MKECFeQbPUhgb6v4FntwdzMPuVqZmFUBLzb' 104 | b'YzU1RCoaOSXvTJ3yCC2_uTez_-uSKXYiFtZRnVZbJEk6GGVI60GT-SS-CS51IBMc9JWAhOSg-JOvnJJsWhvgbCwoZkaUpJ2jNWCCb' 105 | b'pRjFPQEu9GoH-bORbfV2O7b3O3WjtQ8_DA__WX_Zzrhe01HsZ04_7rT75BR7r7fmtwmU4pcmcpFBmcNjdX_-YSohCsgxJriEIq31b' 106 | b'PA79658jFjnheEqegHaTBo98F8rV5gYolf2y5jERnRYmrieNMWHmkzSlt_F2xOCXYbXf7Q65gJ9CYCA_6UlxbuXJLlCkKqr_nUegb' 107 | b'N-PYHpDvG_q4GGpvPiyuIQkO8XK9TqbV_WJWynE_q0pPwC9skMtX_D_m70ZxZOsKwBjngwE9iQrCX-at4TYtaAgzxWDlC30IZh_hb' 108 | b'5qM1uWXVJRV9Fy9kaoJo1ljwf8HqdrD7nyuvNwagqXCkqgvYL7vpymXp_oRYmoVKtx_OzZ3zxGHKgIzrYGsTDsx54XTZjPfGoz7kb' 109 | b'wyaR4wLfmq6WvhRC3N64q-OB7slR8kWZDeBDTsXwVKf4ZgguTL1b9yy79UOxBIHM_SV9WuIk9LhmWoHcEE95TzAC0094NOndhf0rb' 110 | b'PNxt55W5SDZ2WkPUwPl6a-0_ilyrPHSzB7CZyqznLAenHyK6lCBUIsDF5J-kbqu80Tx3K9kv43-0Px2BsQiBbrpI2PKkKYp1Fvf7b' 111 | b'0-hCV0QOcsjIKB_2PBzMjay1MQStEEE8fDNVU9NkBqdv3YjC0W41Lp5x6d0dRywFgqpmjnmxBuG3hvVB5dHEbfieyXoth1i8IZuKb' 112 | b'stZyklQf6UC2EUXsQZp1NdaAUxHNR52veJdg9Jt6E-w0RdaKAP9DrvdM6DzmEPDt4XkrmAzC9v-yTNvnXxhtbwSQAC3NWQs3xCSKb' 113 | b'XXBl5czTZO3tsQELnH5Lu0RuTN7J3SK_Ce1dTn2NS0SYz00fP8jAGrlMBlpJTgTaBx_vXfgeRIT7lq_CjzqbvSqpPlNHeUzTFcZTb' 114 | b'OB8Bq1ZWbRlb_Y2AnDve50tH9VypxL6Cdr6-khON4nCiTcQBwPjTLuh5JTRLL0XfXClgSBYcwUfHSTHg07iIl-KSQqdirQhZjKYLb' 115 | b'BJ4Z-e9xJuQy-SwKJ4yT9rHhYloWmtz6T4jWHaZKy-NPHwr-ztilZtuml_eR5b9khRkJoA6bIGoJEHF_2ycri2vHyUNq8Ym2Wimyb' 116 | b'Whzft7aTUZZKUKSy2q6RZrQEvb0Ltet32UPPJ6FMRiVl_FZJvKWPgTbjHcIChesPPeBy57hm0CDUk6etCNEZpDwfxyyZgtxTDSxab' 117 | b'gnorHBArQxgwC8pKYP4haVhEWhPa3z9CXpTuRTEAzWO1skyFi0P4ydqtt1Mac05yvZb-URbKw2q87Ji2ohFul7gOC-a3WErA4J9cb' 118 | b'ayZ4A5k-OL--uXGPIAxmkElAr0FPBYLLYWPNyUXwNwkV8o8Oxh1K0zeAZV8ccypXwCsmm4x19pifHc7tjaLgV0qJa62M6S9GAhBSb' 119 | b'tIxtbXz0fSfPnYAmbMjOycI9OLNqeRpZ2sEhQq3fWlydLwR2H3CtLRsD7Moh3sCJN36ocOxBWlJh4dt4rafvEOa0KiQBoG9FhqQCb' 120 | b'pu9NhI8SV95MIY9dCI07OGlQy_argVC8GkKZ7ZKtdgZ2UequKSAkRCtw7uGqC54XO1vXAPXwV3Qsx04eLil3X8D816P4dFOIzU4rb' 121 | b'K5nudgDA_H0e2Ym2Gr1cCq7U3JO7KWHXdy7Uqe09CZgzWDucjInnsaLyCDPCTarLi15uzxxgMQN2ncvj788GpE8rN807jYa-5lZsb' 122 | b'VC7liFMF-78IozCbe7VkrGw3VJhVy3_1akkwEYir1Xot0BrC40eYsUkF1Ojw4xOCboH6k-p43XTsyFdVUfT2X_GgwLii00Po4qX6b' 123 | b'R3NlLT5UpF0FiDfllh5YMl9DB5Xa0L1ZewyvglOeJuj32rOsC8wrpq_ytINATyZsJiXf-1gEQj4wG19GmlpklO5dGWMWAw8pUhKyb' 124 | b'1l-EdDXkjL7AkEMGtckt4tULlbMtfN2QYl5mvl56sURYxJ4n5_urAIeKecgplF9FKku_b7e-2VsHnLeG59dlSOIrHRLSx7Jyg7ylb' 125 | b'aWWiEBLZK1oQrchEp3qil3rekd2rBhQty8cCNM4Ez23dtlmGp9WJIk-esVp31OqQN4hnZbP3QX9jm8AeefhHUjnT9uysmYebPjflb' 126 | b'qB4lE4gFR8E5pN0Bb8E8GtTEO3hnUHljYGqzFAx25FvAuoxAJiu2wJWVVnfaxmxXgjbcx8zOvblqfGnXW0T-NHFs76ifaoG0hBUTb' 127 | b'G6KFKSGRLZQVmCW-J1-DwxZlxzUJCRdUfqU7ze7cDF6WmFUcr-bo_VfSAwIn9rvsa-LACRqFAxgU-DshrbrrJ4dv_6ng80Ita6nbb' 128 | b'gMsPxt7zAs4EBtBZP330znjj3bbowAvwBpAyXbmPhVm-hlOs-LDeIyvlt4Pwb' 129 | 130 | params = CommonParams() 131 | checkin = AndroidCheckin(params, SmallProtobufHelper(), str24) 132 | 133 | auth_data = checkin.do_checkin() 134 | 135 | # You can get multiple tokens using this data 136 | print(auth_data) 137 | 138 | login = sys.argv[1] 139 | password = sys.argv[2] 140 | 141 | receiver = TokenReceiver(login, password, auth_data, params) 142 | print(receiver.get_token()) 143 | --------------------------------------------------------------------------------