├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── apkfetch.proto ├── apkfetch.py ├── apkfetch_pb2.py ├── requirements.txt └── util.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Egbert Bouman 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. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # APKfetch 2 | Library for downloading APK files from the Google Play store. 3 | 4 | 5 | ### Dependencies 6 | * Python 2.7+ 7 | * requests 8 | * protobuf 9 | * PyCryptodome 10 | 11 | The Python packages can be installed with 12 | 13 | pip install -r requirements.txt 14 | 15 | 16 | ### Using the library 17 | 18 | Using the library is as simple as: 19 | 20 | ```python 21 | from APKfetch.apkfetch import APKfetch 22 | 23 | def main(): 24 | apk = APKfetch() 25 | apk.login('you@gmail.com', 'yourpassword') 26 | apk.fetch('com.somepackage') 27 | 28 | if __name__ == '__main__': 29 | main() 30 | ``` 31 | 32 | Note that the example creates a new android id. If you wish to use an existing id, you should login using: 33 | 34 | ```python 35 | apk.login('you@gmail.com', 'yourpassword', 'yourandroidid') 36 | ``` 37 | 38 | ### Using the CLI 39 | 40 | ``` 41 | usage: apkfetch.py [--help] [--user USER] [--passwd PASSWD] 42 | [--androidid ANDROIDID] [--version VERSION] 43 | [--package PACKAGE] 44 | 45 | Fetch APK files from the Google Play store 46 | 47 | optional arguments: 48 | --help, -h Show this help message and exit 49 | --user USER, -u USER Google username 50 | --passwd PASSWD, -p PASSWD 51 | Google password 52 | --androidid ANDROIDID, -a ANDROIDID 53 | AndroidID 54 | --version VERSION, -v VERSION 55 | Download a specific version of the app 56 | --package PACKAGE, -k PACKAGE 57 | Package name of the app 58 | ``` -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/egbertbouman/APKfetch/f1636a759f58ef20aab155f6f1d36e4d0819a61e/__init__.py -------------------------------------------------------------------------------- /apkfetch.proto: -------------------------------------------------------------------------------- 1 | // Note: messages only include fields needed for APKfetch to work 2 | 3 | message AndroidCheckinRequest { 4 | optional int64 id = 2; 5 | optional AndroidCheckinProto checkin = 4; 6 | optional string marketCheckin = 8; 7 | repeated string accountCookie = 11; 8 | optional int32 version = 14; 9 | optional DeviceConfigurationProto deviceConfiguration = 18; 10 | optional int32 fragment = 20; 11 | } 12 | message AndroidCheckinProto { 13 | optional AndroidBuildProto build = 1; 14 | } 15 | message AndroidBuildProto { 16 | optional int64 timestamp = 7; 17 | optional int32 sdkVersion = 10; 18 | } 19 | message DeviceConfigurationProto { 20 | optional int32 touchScreen = 1; 21 | optional int32 keyboard = 2; 22 | optional int32 navigation = 3; 23 | optional int32 screenLayout = 4; 24 | optional bool hasHardKeyboard = 5; 25 | optional bool hasFiveWayNavigation = 6; 26 | optional int32 screenDensity = 7; 27 | optional int32 glEsVersion = 8; 28 | repeated string systemSharedLibrary = 9; 29 | repeated string systemAvailableFeature = 10; 30 | repeated string nativePlatform = 11; 31 | optional int32 screenWidth = 12; 32 | optional int32 screenHeight = 13; 33 | } 34 | message AndroidCheckinResponse { 35 | optional fixed64 androidId = 7; 36 | optional fixed64 securityToken = 8; 37 | } 38 | message ResponseWrapper { 39 | optional Payload payload = 1; 40 | optional ServerCommands commands = 2; 41 | } 42 | message ServerCommands { 43 | optional string displayErrorMessage = 2; 44 | } 45 | message Payload { 46 | optional DetailsResponse detailsResponse = 2; 47 | optional BuyResponse buyResponse = 4; 48 | optional DeliveryResponse deliveryResponse = 21; 49 | } 50 | message BuyResponse { 51 | optional PurchaseStatusResponse purchaseStatusResponse = 39; 52 | } 53 | message PurchaseStatusResponse { 54 | optional AndroidAppDeliveryData appDeliveryData = 8; 55 | } 56 | message AndroidAppDeliveryData { 57 | optional string downloadUrl = 3; 58 | repeated HttpCookie downloadAuthCookie = 5; 59 | } 60 | message HttpCookie { 61 | optional string name = 1; 62 | optional string value = 2; 63 | } 64 | message DetailsResponse { 65 | optional DocV2 docV2 = 4; 66 | } 67 | message DocV2 { 68 | optional DocumentDetails details = 13; 69 | } 70 | message DocumentDetails { 71 | optional AppDetails appDetails = 1; 72 | } 73 | message AppDetails { 74 | optional int32 versionCode = 3; 75 | } 76 | message DeliveryResponse { 77 | optional int32 status = 1; 78 | optional AndroidAppDeliveryData appDeliveryData = 2; 79 | } 80 | -------------------------------------------------------------------------------- /apkfetch.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os 4 | import sys 5 | import json 6 | import gzip 7 | import time 8 | import argparse 9 | import requests 10 | 11 | import apkfetch_pb2 12 | 13 | from util import encrypt 14 | 15 | GOOGLE_LOGIN_URL = 'https://android.clients.google.com/auth' 16 | GOOGLE_CHECKIN_URL = 'https://android.clients.google.com/checkin' 17 | GOOGLE_DETAILS_URL = 'https://android.clients.google.com/fdfe/details' 18 | GOOGLE_DELIVERY_URL = 'https://android.clients.google.com/fdfe/delivery' 19 | 20 | LOGIN_USER_AGENT = 'GoogleLoginService/1.3 (gio KOT49H)' 21 | MARKET_USER_AGENT = 'Android-Finsky/5.7.10 (api=3,versionCode=80371000,sdk=24,device=falcon_umts,hardware=qcom,product=falcon_reteu,platformVersionRelease=4.4.4,model=XT1032,buildId=KXB21.14-L1.40,isWideScreen=0)' 22 | CHECKIN_USER_AGENT = 'Android-Checkin/2.0 (gio KOT49H)' 23 | DOWNLOAD_USER_AGENT = 'AndroidDownloadManager/4.4.4 (Linux; U; Android 4.4.4; XT1032 Build/KXB21.14-L1.40)' 24 | 25 | 26 | def num_to_hex(num): 27 | hex_str = format(num, 'x') 28 | length = len(hex_str) 29 | return hex_str.zfill(length + length % 2) 30 | 31 | 32 | class APKfetch(object): 33 | 34 | def __init__(self): 35 | self.session = requests.Session() 36 | self.user = self.passwd = self.androidid = self.token = self.auth = None 37 | 38 | def request_service(self, service, app, user_agent=LOGIN_USER_AGENT): 39 | self.session.headers.update({'User-Agent': user_agent, 40 | 'Content-Type': 'application/x-www-form-urlencoded'}) 41 | 42 | if self.androidid: 43 | self.session.headers.update({'device': self.androidid}) 44 | 45 | data = {'accountType': 'HOSTED_OR_GOOGLE', 46 | 'has_permission': '1', 47 | 'add_account': '1', 48 | 'get_accountid': '1', 49 | 'service': service, 50 | 'app': app, 51 | 'source': 'android', 52 | 'Email': self.user} 53 | 54 | if self.androidid: 55 | data['androidId'] = self.androidid 56 | 57 | data['EncryptedPasswd'] = self.token or encrypt(self.user, self.passwd) 58 | 59 | response = self.session.post(GOOGLE_LOGIN_URL, data=data, allow_redirects=True) 60 | response_values = dict([line.split('=', 1) for line in response.text.splitlines()]) 61 | 62 | if 'Error' in response_values: 63 | error_msg = response_values.get('ErrorDetail', None) or response_values.get('Error') 64 | if 'Url' in response_values: 65 | error_msg += '\n\nTo resolve the issue, visit: ' + response_values['Url'] 66 | error_msg += '\n\nOr try: https://accounts.google.com/b/0/DisplayUnlockCaptcha' 67 | raise RuntimeError(error_msg) 68 | elif 'Auth' not in response_values: 69 | raise RuntimeError('Could not login') 70 | 71 | return response_values.get('Token', None), response_values.get('Auth') 72 | 73 | def checkin(self): 74 | headers = {'User-Agent': CHECKIN_USER_AGENT, 75 | 'Content-Type': 'application/x-protobuf'} 76 | 77 | cr = apkfetch_pb2.AndroidCheckinRequest() 78 | cr.id = 0 79 | cr.checkin.build.timestamp = int(time.time()) 80 | cr.checkin.build.sdkVersion = 16 81 | cr.marketCheckin = self.user 82 | cr.accountCookie.append(self.auth[5:]) 83 | cr.deviceConfiguration.touchScreen = 3 84 | cr.deviceConfiguration.keyboard = 1 85 | cr.deviceConfiguration.navigation = 1 86 | cr.deviceConfiguration.screenLayout = 2 87 | cr.deviceConfiguration.hasHardKeyboard = False 88 | cr.deviceConfiguration.hasFiveWayNavigation = False 89 | cr.deviceConfiguration.screenDensity = 320 90 | cr.deviceConfiguration.glEsVersion = 131072 91 | cr.deviceConfiguration.systemSharedLibrary.extend(["android.test.runner", "com.android.future.usb.accessory", 92 | "com.android.location.provider", "com.android.nfc_extras", 93 | "com.google.android.maps", "com.google.android.media.effects", 94 | "com.google.widevine.software.drm", "javax.obex"]) 95 | cr.deviceConfiguration.systemAvailableFeature.extend(["android.hardware.bluetooth", "android.hardware.camera", 96 | "android.hardware.camera.autofocus", "android.hardware.camera.flash", 97 | "android.hardware.camera.front", "android.hardware.faketouch", 98 | "android.hardware.location", "android.hardware.location.gps", 99 | "android.hardware.location.network", "android.hardware.microphone", 100 | "android.hardware.nfc", "android.hardware.screen.landscape", 101 | "android.hardware.screen.portrait", "android.hardware.sensor.accelerometer", 102 | "android.hardware.sensor.barometer", "android.hardware.sensor.compass", 103 | "android.hardware.sensor.gyroscope", "android.hardware.sensor.light", 104 | "android.hardware.sensor.proximity", "android.hardware.telephony", 105 | "android.hardware.telephony.gsm", "android.hardware.touchscreen", 106 | "android.hardware.touchscreen.multitouch", 107 | "android.hardware.touchscreen.multitouch.distinct", 108 | "android.hardware.touchscreen.multitouch.jazzhand", 109 | "android.hardware.usb.accessory", "android.hardware.usb.host", 110 | "android.hardware.wifi", "android.hardware.wifi.direct", 111 | "android.software.live_wallpaper", "android.software.sip", 112 | "android.software.sip.voip", 113 | "com.google.android.feature.GOOGLE_BUILD", "com.nxp.mifare"]) 114 | cr.deviceConfiguration.nativePlatform.extend(["armeabi-v7a", "armeabi"]) 115 | cr.deviceConfiguration.screenWidth = 720 116 | cr.deviceConfiguration.screenHeight = 1280 117 | cr.version = 3 118 | cr.fragment = 0 119 | 120 | response = self.session.post(GOOGLE_CHECKIN_URL, data=cr.SerializeToString(), headers=headers, allow_redirects=True) 121 | 122 | checkin_response = apkfetch_pb2.AndroidCheckinResponse() 123 | checkin_response.ParseFromString(response.content) 124 | token = num_to_hex(checkin_response.securityToken) 125 | androidid = num_to_hex(checkin_response.androidId) 126 | return token, androidid 127 | 128 | def login(self, user, passwd, androidid=None): 129 | self.user = user 130 | self.passwd = passwd 131 | self.androidid = androidid 132 | 133 | self.token, self.auth = self.request_service('ac2dm', 'com.google.android.gsf') 134 | 135 | if not androidid: 136 | _, self.androidid = self.checkin() 137 | 138 | _, self.auth = self.request_service('androidmarket', 'com.android.vending', MARKET_USER_AGENT) 139 | 140 | return self.auth is not None 141 | 142 | def version(self, package_name): 143 | headers = {'X-DFE-Device-Id': self.androidid, 144 | 'X-DFE-Client-Id': 'am-android-google', 145 | 'Accept-Encoding': '', 146 | 'Host': 'android.clients.google.com', 147 | 'Authorization': 'GoogleLogin Auth=' + self.auth, 148 | 'User-Agent': MARKET_USER_AGENT} 149 | 150 | params = {'doc': package_name} 151 | response = self.session.get(GOOGLE_DETAILS_URL, params=params, headers=headers, allow_redirects=True) 152 | 153 | details_response = apkfetch_pb2.ResponseWrapper() 154 | details_response.ParseFromString(response.content) 155 | version = details_response.payload.detailsResponse.docV2.details.appDetails.versionCode 156 | if not version: 157 | raise RuntimeError('Could not get version-code') 158 | return version 159 | 160 | def get_download_url(self, package_name, version_code): 161 | headers = {'X-DFE-Device-Id': self.androidid, 162 | 'X-DFE-Client-Id': 'am-android-google', 163 | 'Accept-Encoding': '', 164 | 'Host': 'android.clients.google.com', 165 | 'Authorization': 'GoogleLogin Auth=' + self.auth} 166 | 167 | data = {'doc': package_name, 168 | 'ot': '1', 169 | 'vc': version_code} 170 | 171 | response = self.session.get(GOOGLE_DELIVERY_URL, params=data, headers=headers, allow_redirects=True) 172 | delivery_response = apkfetch_pb2.ResponseWrapper() 173 | delivery_response.ParseFromString(response.content) 174 | url = delivery_response.payload.deliveryResponse.appDeliveryData.downloadUrl 175 | return url 176 | 177 | def list(self, package_name): 178 | vc_new = self.version(package_name) 179 | for vc in xrange(vc_new, -1, -1): 180 | url = self.get_download_url(package_name, vc) 181 | if url: 182 | yield vc 183 | 184 | def fetch(self, package_name, version_code, apk_fn=None): 185 | url = self.get_download_url(package_name, version_code) 186 | if not url: 187 | raise RuntimeError('Could not get download URL') 188 | 189 | response = self.session.get(url, headers={'User-Agent': DOWNLOAD_USER_AGENT}, 190 | stream=True, allow_redirects=True) 191 | 192 | apk_fn = apk_fn or (package_name + '.apk') 193 | if os.path.exists(apk_fn): 194 | os.remove(apk_fn) 195 | 196 | with open(apk_fn, 'wb') as fp: 197 | for chunk in response.iter_content(chunk_size=5*1024): 198 | if chunk: 199 | fp.write(chunk) 200 | fp.flush() 201 | 202 | return os.path.exists(apk_fn) 203 | 204 | 205 | def main(argv): 206 | parser = argparse.ArgumentParser(add_help=False, description=('Fetch APK files from the Google Play store')) 207 | parser.add_argument('--help', '-h', action='help', default=argparse.SUPPRESS, help='Show this help message and exit') 208 | parser.add_argument('--user', '-u', help='Google username') 209 | parser.add_argument('--passwd', '-p', help='Google password') 210 | parser.add_argument('--androidid', '-a', help='AndroidID') 211 | parser.add_argument('--package', '-k', help='Package name of the app') 212 | parser.add_argument('--version', '-v', help='Download a specific version of the app') 213 | parser.add_argument('--search', '-s', help='Find all versions of the app that are available', action='store_true') 214 | 215 | try: 216 | args = parser.parse_args(sys.argv[1:]) 217 | 218 | user = args.user 219 | passwd = args.passwd 220 | androidid = args.androidid 221 | package = args.package 222 | version = args.version 223 | 224 | if not user or not passwd or not package: 225 | parser.print_usage() 226 | raise ValueError('user, passwd, and package are required options') 227 | 228 | apk = APKfetch() 229 | apk.login(user, passwd, androidid) 230 | 231 | if not androidid and apk.androidid: 232 | print('AndroidID', apk.androidid) 233 | 234 | if args.search: 235 | print('The following versions are available:', end = '') 236 | for vc in apk.list(package): 237 | print(' %d' % vc, end = '') 238 | # We don't want to get blocked.. 239 | time.sleep(1) 240 | print('') 241 | else: 242 | version = version or apk.version(package) 243 | if apk.fetch(package, version): 244 | print('Downloaded version', version) 245 | 246 | except Exception as e: 247 | print('Error:', str(e)) 248 | sys.exit(1) 249 | 250 | 251 | if __name__ == "__main__": 252 | main(sys.argv[1:]) 253 | -------------------------------------------------------------------------------- /apkfetch_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: apkfetch.proto 3 | 4 | import sys 5 | _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import message as _message 8 | from google.protobuf import reflection as _reflection 9 | from google.protobuf import symbol_database as _symbol_database 10 | from google.protobuf import descriptor_pb2 11 | # @@protoc_insertion_point(imports) 12 | 13 | _sym_db = _symbol_database.Default() 14 | 15 | 16 | 17 | 18 | DESCRIPTOR = _descriptor.FileDescriptor( 19 | name='apkfetch.proto', 20 | package='', 21 | syntax='proto2', 22 | serialized_pb=_b('\n\x0e\x61pkfetch.proto\"\xd3\x01\n\x15\x41ndroidCheckinRequest\x12\n\n\x02id\x18\x02 \x01(\x03\x12%\n\x07\x63heckin\x18\x04 \x01(\x0b\x32\x14.AndroidCheckinProto\x12\x15\n\rmarketCheckin\x18\x08 \x01(\t\x12\x15\n\raccountCookie\x18\x0b \x03(\t\x12\x0f\n\x07version\x18\x0e \x01(\x05\x12\x36\n\x13\x64\x65viceConfiguration\x18\x12 \x01(\x0b\x32\x19.DeviceConfigurationProto\x12\x10\n\x08\x66ragment\x18\x14 \x01(\x05\"8\n\x13\x41ndroidCheckinProto\x12!\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x12.AndroidBuildProto\":\n\x11\x41ndroidBuildProto\x12\x11\n\ttimestamp\x18\x07 \x01(\x03\x12\x12\n\nsdkVersion\x18\n \x01(\x05\"\xce\x02\n\x18\x44\x65viceConfigurationProto\x12\x13\n\x0btouchScreen\x18\x01 \x01(\x05\x12\x10\n\x08keyboard\x18\x02 \x01(\x05\x12\x12\n\nnavigation\x18\x03 \x01(\x05\x12\x14\n\x0cscreenLayout\x18\x04 \x01(\x05\x12\x17\n\x0fhasHardKeyboard\x18\x05 \x01(\x08\x12\x1c\n\x14hasFiveWayNavigation\x18\x06 \x01(\x08\x12\x15\n\rscreenDensity\x18\x07 \x01(\x05\x12\x13\n\x0bglEsVersion\x18\x08 \x01(\x05\x12\x1b\n\x13systemSharedLibrary\x18\t \x03(\t\x12\x1e\n\x16systemAvailableFeature\x18\n \x03(\t\x12\x16\n\x0enativePlatform\x18\x0b \x03(\t\x12\x13\n\x0bscreenWidth\x18\x0c \x01(\x05\x12\x14\n\x0cscreenHeight\x18\r \x01(\x05\"B\n\x16\x41ndroidCheckinResponse\x12\x11\n\tandroidId\x18\x07 \x01(\x06\x12\x15\n\rsecurityToken\x18\x08 \x01(\x06\"O\n\x0fResponseWrapper\x12\x19\n\x07payload\x18\x01 \x01(\x0b\x32\x08.Payload\x12!\n\x08\x63ommands\x18\x02 \x01(\x0b\x32\x0f.ServerCommands\"-\n\x0eServerCommands\x12\x1b\n\x13\x64isplayErrorMessage\x18\x02 \x01(\t\"\x84\x01\n\x07Payload\x12)\n\x0f\x64\x65tailsResponse\x18\x02 \x01(\x0b\x32\x10.DetailsResponse\x12!\n\x0b\x62uyResponse\x18\x04 \x01(\x0b\x32\x0c.BuyResponse\x12+\n\x10\x64\x65liveryResponse\x18\x15 \x01(\x0b\x32\x11.DeliveryResponse\"F\n\x0b\x42uyResponse\x12\x37\n\x16purchaseStatusResponse\x18\' \x01(\x0b\x32\x17.PurchaseStatusResponse\"J\n\x16PurchaseStatusResponse\x12\x30\n\x0f\x61ppDeliveryData\x18\x08 \x01(\x0b\x32\x17.AndroidAppDeliveryData\"V\n\x16\x41ndroidAppDeliveryData\x12\x13\n\x0b\x64ownloadUrl\x18\x03 \x01(\t\x12\'\n\x12\x64ownloadAuthCookie\x18\x05 \x03(\x0b\x32\x0b.HttpCookie\")\n\nHttpCookie\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"(\n\x0f\x44\x65tailsResponse\x12\x15\n\x05\x64ocV2\x18\x04 \x01(\x0b\x32\x06.DocV2\"*\n\x05\x44ocV2\x12!\n\x07\x64\x65tails\x18\r \x01(\x0b\x32\x10.DocumentDetails\"2\n\x0f\x44ocumentDetails\x12\x1f\n\nappDetails\x18\x01 \x01(\x0b\x32\x0b.AppDetails\"!\n\nAppDetails\x12\x13\n\x0bversionCode\x18\x03 \x01(\x05\"T\n\x10\x44\x65liveryResponse\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x30\n\x0f\x61ppDeliveryData\x18\x02 \x01(\x0b\x32\x17.AndroidAppDeliveryData') 23 | ) 24 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 25 | 26 | 27 | 28 | 29 | _ANDROIDCHECKINREQUEST = _descriptor.Descriptor( 30 | name='AndroidCheckinRequest', 31 | full_name='AndroidCheckinRequest', 32 | filename=None, 33 | file=DESCRIPTOR, 34 | containing_type=None, 35 | fields=[ 36 | _descriptor.FieldDescriptor( 37 | name='id', full_name='AndroidCheckinRequest.id', index=0, 38 | number=2, type=3, cpp_type=2, label=1, 39 | has_default_value=False, default_value=0, 40 | message_type=None, enum_type=None, containing_type=None, 41 | is_extension=False, extension_scope=None, 42 | options=None), 43 | _descriptor.FieldDescriptor( 44 | name='checkin', full_name='AndroidCheckinRequest.checkin', index=1, 45 | number=4, type=11, cpp_type=10, label=1, 46 | has_default_value=False, default_value=None, 47 | message_type=None, enum_type=None, containing_type=None, 48 | is_extension=False, extension_scope=None, 49 | options=None), 50 | _descriptor.FieldDescriptor( 51 | name='marketCheckin', full_name='AndroidCheckinRequest.marketCheckin', index=2, 52 | number=8, type=9, cpp_type=9, label=1, 53 | has_default_value=False, default_value=_b("").decode('utf-8'), 54 | message_type=None, enum_type=None, containing_type=None, 55 | is_extension=False, extension_scope=None, 56 | options=None), 57 | _descriptor.FieldDescriptor( 58 | name='accountCookie', full_name='AndroidCheckinRequest.accountCookie', index=3, 59 | number=11, type=9, cpp_type=9, label=3, 60 | has_default_value=False, default_value=[], 61 | message_type=None, enum_type=None, containing_type=None, 62 | is_extension=False, extension_scope=None, 63 | options=None), 64 | _descriptor.FieldDescriptor( 65 | name='version', full_name='AndroidCheckinRequest.version', index=4, 66 | number=14, type=5, cpp_type=1, label=1, 67 | has_default_value=False, default_value=0, 68 | message_type=None, enum_type=None, containing_type=None, 69 | is_extension=False, extension_scope=None, 70 | options=None), 71 | _descriptor.FieldDescriptor( 72 | name='deviceConfiguration', full_name='AndroidCheckinRequest.deviceConfiguration', index=5, 73 | number=18, type=11, cpp_type=10, label=1, 74 | has_default_value=False, default_value=None, 75 | message_type=None, enum_type=None, containing_type=None, 76 | is_extension=False, extension_scope=None, 77 | options=None), 78 | _descriptor.FieldDescriptor( 79 | name='fragment', full_name='AndroidCheckinRequest.fragment', index=6, 80 | number=20, type=5, cpp_type=1, label=1, 81 | has_default_value=False, default_value=0, 82 | message_type=None, enum_type=None, containing_type=None, 83 | is_extension=False, extension_scope=None, 84 | options=None), 85 | ], 86 | extensions=[ 87 | ], 88 | nested_types=[], 89 | enum_types=[ 90 | ], 91 | options=None, 92 | is_extendable=False, 93 | syntax='proto2', 94 | extension_ranges=[], 95 | oneofs=[ 96 | ], 97 | serialized_start=19, 98 | serialized_end=230, 99 | ) 100 | 101 | 102 | _ANDROIDCHECKINPROTO = _descriptor.Descriptor( 103 | name='AndroidCheckinProto', 104 | full_name='AndroidCheckinProto', 105 | filename=None, 106 | file=DESCRIPTOR, 107 | containing_type=None, 108 | fields=[ 109 | _descriptor.FieldDescriptor( 110 | name='build', full_name='AndroidCheckinProto.build', index=0, 111 | number=1, type=11, cpp_type=10, label=1, 112 | has_default_value=False, default_value=None, 113 | message_type=None, enum_type=None, containing_type=None, 114 | is_extension=False, extension_scope=None, 115 | options=None), 116 | ], 117 | extensions=[ 118 | ], 119 | nested_types=[], 120 | enum_types=[ 121 | ], 122 | options=None, 123 | is_extendable=False, 124 | syntax='proto2', 125 | extension_ranges=[], 126 | oneofs=[ 127 | ], 128 | serialized_start=232, 129 | serialized_end=288, 130 | ) 131 | 132 | 133 | _ANDROIDBUILDPROTO = _descriptor.Descriptor( 134 | name='AndroidBuildProto', 135 | full_name='AndroidBuildProto', 136 | filename=None, 137 | file=DESCRIPTOR, 138 | containing_type=None, 139 | fields=[ 140 | _descriptor.FieldDescriptor( 141 | name='timestamp', full_name='AndroidBuildProto.timestamp', index=0, 142 | number=7, type=3, cpp_type=2, label=1, 143 | has_default_value=False, default_value=0, 144 | message_type=None, enum_type=None, containing_type=None, 145 | is_extension=False, extension_scope=None, 146 | options=None), 147 | _descriptor.FieldDescriptor( 148 | name='sdkVersion', full_name='AndroidBuildProto.sdkVersion', index=1, 149 | number=10, type=5, cpp_type=1, label=1, 150 | has_default_value=False, default_value=0, 151 | message_type=None, enum_type=None, containing_type=None, 152 | is_extension=False, extension_scope=None, 153 | options=None), 154 | ], 155 | extensions=[ 156 | ], 157 | nested_types=[], 158 | enum_types=[ 159 | ], 160 | options=None, 161 | is_extendable=False, 162 | syntax='proto2', 163 | extension_ranges=[], 164 | oneofs=[ 165 | ], 166 | serialized_start=290, 167 | serialized_end=348, 168 | ) 169 | 170 | 171 | _DEVICECONFIGURATIONPROTO = _descriptor.Descriptor( 172 | name='DeviceConfigurationProto', 173 | full_name='DeviceConfigurationProto', 174 | filename=None, 175 | file=DESCRIPTOR, 176 | containing_type=None, 177 | fields=[ 178 | _descriptor.FieldDescriptor( 179 | name='touchScreen', full_name='DeviceConfigurationProto.touchScreen', index=0, 180 | number=1, type=5, cpp_type=1, label=1, 181 | has_default_value=False, default_value=0, 182 | message_type=None, enum_type=None, containing_type=None, 183 | is_extension=False, extension_scope=None, 184 | options=None), 185 | _descriptor.FieldDescriptor( 186 | name='keyboard', full_name='DeviceConfigurationProto.keyboard', index=1, 187 | number=2, type=5, cpp_type=1, label=1, 188 | has_default_value=False, default_value=0, 189 | message_type=None, enum_type=None, containing_type=None, 190 | is_extension=False, extension_scope=None, 191 | options=None), 192 | _descriptor.FieldDescriptor( 193 | name='navigation', full_name='DeviceConfigurationProto.navigation', index=2, 194 | number=3, type=5, cpp_type=1, label=1, 195 | has_default_value=False, default_value=0, 196 | message_type=None, enum_type=None, containing_type=None, 197 | is_extension=False, extension_scope=None, 198 | options=None), 199 | _descriptor.FieldDescriptor( 200 | name='screenLayout', full_name='DeviceConfigurationProto.screenLayout', index=3, 201 | number=4, type=5, cpp_type=1, label=1, 202 | has_default_value=False, default_value=0, 203 | message_type=None, enum_type=None, containing_type=None, 204 | is_extension=False, extension_scope=None, 205 | options=None), 206 | _descriptor.FieldDescriptor( 207 | name='hasHardKeyboard', full_name='DeviceConfigurationProto.hasHardKeyboard', index=4, 208 | number=5, type=8, cpp_type=7, label=1, 209 | has_default_value=False, default_value=False, 210 | message_type=None, enum_type=None, containing_type=None, 211 | is_extension=False, extension_scope=None, 212 | options=None), 213 | _descriptor.FieldDescriptor( 214 | name='hasFiveWayNavigation', full_name='DeviceConfigurationProto.hasFiveWayNavigation', index=5, 215 | number=6, type=8, cpp_type=7, label=1, 216 | has_default_value=False, default_value=False, 217 | message_type=None, enum_type=None, containing_type=None, 218 | is_extension=False, extension_scope=None, 219 | options=None), 220 | _descriptor.FieldDescriptor( 221 | name='screenDensity', full_name='DeviceConfigurationProto.screenDensity', index=6, 222 | number=7, type=5, cpp_type=1, label=1, 223 | has_default_value=False, default_value=0, 224 | message_type=None, enum_type=None, containing_type=None, 225 | is_extension=False, extension_scope=None, 226 | options=None), 227 | _descriptor.FieldDescriptor( 228 | name='glEsVersion', full_name='DeviceConfigurationProto.glEsVersion', index=7, 229 | number=8, type=5, cpp_type=1, label=1, 230 | has_default_value=False, default_value=0, 231 | message_type=None, enum_type=None, containing_type=None, 232 | is_extension=False, extension_scope=None, 233 | options=None), 234 | _descriptor.FieldDescriptor( 235 | name='systemSharedLibrary', full_name='DeviceConfigurationProto.systemSharedLibrary', index=8, 236 | number=9, type=9, cpp_type=9, label=3, 237 | has_default_value=False, default_value=[], 238 | message_type=None, enum_type=None, containing_type=None, 239 | is_extension=False, extension_scope=None, 240 | options=None), 241 | _descriptor.FieldDescriptor( 242 | name='systemAvailableFeature', full_name='DeviceConfigurationProto.systemAvailableFeature', index=9, 243 | number=10, type=9, cpp_type=9, label=3, 244 | has_default_value=False, default_value=[], 245 | message_type=None, enum_type=None, containing_type=None, 246 | is_extension=False, extension_scope=None, 247 | options=None), 248 | _descriptor.FieldDescriptor( 249 | name='nativePlatform', full_name='DeviceConfigurationProto.nativePlatform', index=10, 250 | number=11, type=9, cpp_type=9, label=3, 251 | has_default_value=False, default_value=[], 252 | message_type=None, enum_type=None, containing_type=None, 253 | is_extension=False, extension_scope=None, 254 | options=None), 255 | _descriptor.FieldDescriptor( 256 | name='screenWidth', full_name='DeviceConfigurationProto.screenWidth', index=11, 257 | number=12, type=5, cpp_type=1, label=1, 258 | has_default_value=False, default_value=0, 259 | message_type=None, enum_type=None, containing_type=None, 260 | is_extension=False, extension_scope=None, 261 | options=None), 262 | _descriptor.FieldDescriptor( 263 | name='screenHeight', full_name='DeviceConfigurationProto.screenHeight', index=12, 264 | number=13, type=5, cpp_type=1, label=1, 265 | has_default_value=False, default_value=0, 266 | message_type=None, enum_type=None, containing_type=None, 267 | is_extension=False, extension_scope=None, 268 | options=None), 269 | ], 270 | extensions=[ 271 | ], 272 | nested_types=[], 273 | enum_types=[ 274 | ], 275 | options=None, 276 | is_extendable=False, 277 | syntax='proto2', 278 | extension_ranges=[], 279 | oneofs=[ 280 | ], 281 | serialized_start=351, 282 | serialized_end=685, 283 | ) 284 | 285 | 286 | _ANDROIDCHECKINRESPONSE = _descriptor.Descriptor( 287 | name='AndroidCheckinResponse', 288 | full_name='AndroidCheckinResponse', 289 | filename=None, 290 | file=DESCRIPTOR, 291 | containing_type=None, 292 | fields=[ 293 | _descriptor.FieldDescriptor( 294 | name='androidId', full_name='AndroidCheckinResponse.androidId', index=0, 295 | number=7, type=6, cpp_type=4, label=1, 296 | has_default_value=False, default_value=0, 297 | message_type=None, enum_type=None, containing_type=None, 298 | is_extension=False, extension_scope=None, 299 | options=None), 300 | _descriptor.FieldDescriptor( 301 | name='securityToken', full_name='AndroidCheckinResponse.securityToken', index=1, 302 | number=8, type=6, cpp_type=4, label=1, 303 | has_default_value=False, default_value=0, 304 | message_type=None, enum_type=None, containing_type=None, 305 | is_extension=False, extension_scope=None, 306 | options=None), 307 | ], 308 | extensions=[ 309 | ], 310 | nested_types=[], 311 | enum_types=[ 312 | ], 313 | options=None, 314 | is_extendable=False, 315 | syntax='proto2', 316 | extension_ranges=[], 317 | oneofs=[ 318 | ], 319 | serialized_start=687, 320 | serialized_end=753, 321 | ) 322 | 323 | 324 | _RESPONSEWRAPPER = _descriptor.Descriptor( 325 | name='ResponseWrapper', 326 | full_name='ResponseWrapper', 327 | filename=None, 328 | file=DESCRIPTOR, 329 | containing_type=None, 330 | fields=[ 331 | _descriptor.FieldDescriptor( 332 | name='payload', full_name='ResponseWrapper.payload', index=0, 333 | number=1, type=11, cpp_type=10, label=1, 334 | has_default_value=False, default_value=None, 335 | message_type=None, enum_type=None, containing_type=None, 336 | is_extension=False, extension_scope=None, 337 | options=None), 338 | _descriptor.FieldDescriptor( 339 | name='commands', full_name='ResponseWrapper.commands', index=1, 340 | number=2, type=11, cpp_type=10, label=1, 341 | has_default_value=False, default_value=None, 342 | message_type=None, enum_type=None, containing_type=None, 343 | is_extension=False, extension_scope=None, 344 | options=None), 345 | ], 346 | extensions=[ 347 | ], 348 | nested_types=[], 349 | enum_types=[ 350 | ], 351 | options=None, 352 | is_extendable=False, 353 | syntax='proto2', 354 | extension_ranges=[], 355 | oneofs=[ 356 | ], 357 | serialized_start=755, 358 | serialized_end=834, 359 | ) 360 | 361 | 362 | _SERVERCOMMANDS = _descriptor.Descriptor( 363 | name='ServerCommands', 364 | full_name='ServerCommands', 365 | filename=None, 366 | file=DESCRIPTOR, 367 | containing_type=None, 368 | fields=[ 369 | _descriptor.FieldDescriptor( 370 | name='displayErrorMessage', full_name='ServerCommands.displayErrorMessage', index=0, 371 | number=2, type=9, cpp_type=9, label=1, 372 | has_default_value=False, default_value=_b("").decode('utf-8'), 373 | message_type=None, enum_type=None, containing_type=None, 374 | is_extension=False, extension_scope=None, 375 | options=None), 376 | ], 377 | extensions=[ 378 | ], 379 | nested_types=[], 380 | enum_types=[ 381 | ], 382 | options=None, 383 | is_extendable=False, 384 | syntax='proto2', 385 | extension_ranges=[], 386 | oneofs=[ 387 | ], 388 | serialized_start=836, 389 | serialized_end=881, 390 | ) 391 | 392 | 393 | _PAYLOAD = _descriptor.Descriptor( 394 | name='Payload', 395 | full_name='Payload', 396 | filename=None, 397 | file=DESCRIPTOR, 398 | containing_type=None, 399 | fields=[ 400 | _descriptor.FieldDescriptor( 401 | name='detailsResponse', full_name='Payload.detailsResponse', index=0, 402 | number=2, type=11, cpp_type=10, label=1, 403 | has_default_value=False, default_value=None, 404 | message_type=None, enum_type=None, containing_type=None, 405 | is_extension=False, extension_scope=None, 406 | options=None), 407 | _descriptor.FieldDescriptor( 408 | name='buyResponse', full_name='Payload.buyResponse', index=1, 409 | number=4, type=11, cpp_type=10, label=1, 410 | has_default_value=False, default_value=None, 411 | message_type=None, enum_type=None, containing_type=None, 412 | is_extension=False, extension_scope=None, 413 | options=None), 414 | _descriptor.FieldDescriptor( 415 | name='deliveryResponse', full_name='Payload.deliveryResponse', index=2, 416 | number=21, type=11, cpp_type=10, label=1, 417 | has_default_value=False, default_value=None, 418 | message_type=None, enum_type=None, containing_type=None, 419 | is_extension=False, extension_scope=None, 420 | options=None), 421 | ], 422 | extensions=[ 423 | ], 424 | nested_types=[], 425 | enum_types=[ 426 | ], 427 | options=None, 428 | is_extendable=False, 429 | syntax='proto2', 430 | extension_ranges=[], 431 | oneofs=[ 432 | ], 433 | serialized_start=884, 434 | serialized_end=1016, 435 | ) 436 | 437 | 438 | _BUYRESPONSE = _descriptor.Descriptor( 439 | name='BuyResponse', 440 | full_name='BuyResponse', 441 | filename=None, 442 | file=DESCRIPTOR, 443 | containing_type=None, 444 | fields=[ 445 | _descriptor.FieldDescriptor( 446 | name='purchaseStatusResponse', full_name='BuyResponse.purchaseStatusResponse', index=0, 447 | number=39, type=11, cpp_type=10, label=1, 448 | has_default_value=False, default_value=None, 449 | message_type=None, enum_type=None, containing_type=None, 450 | is_extension=False, extension_scope=None, 451 | options=None), 452 | ], 453 | extensions=[ 454 | ], 455 | nested_types=[], 456 | enum_types=[ 457 | ], 458 | options=None, 459 | is_extendable=False, 460 | syntax='proto2', 461 | extension_ranges=[], 462 | oneofs=[ 463 | ], 464 | serialized_start=1018, 465 | serialized_end=1088, 466 | ) 467 | 468 | 469 | _PURCHASESTATUSRESPONSE = _descriptor.Descriptor( 470 | name='PurchaseStatusResponse', 471 | full_name='PurchaseStatusResponse', 472 | filename=None, 473 | file=DESCRIPTOR, 474 | containing_type=None, 475 | fields=[ 476 | _descriptor.FieldDescriptor( 477 | name='appDeliveryData', full_name='PurchaseStatusResponse.appDeliveryData', index=0, 478 | number=8, type=11, cpp_type=10, label=1, 479 | has_default_value=False, default_value=None, 480 | message_type=None, enum_type=None, containing_type=None, 481 | is_extension=False, extension_scope=None, 482 | options=None), 483 | ], 484 | extensions=[ 485 | ], 486 | nested_types=[], 487 | enum_types=[ 488 | ], 489 | options=None, 490 | is_extendable=False, 491 | syntax='proto2', 492 | extension_ranges=[], 493 | oneofs=[ 494 | ], 495 | serialized_start=1090, 496 | serialized_end=1164, 497 | ) 498 | 499 | 500 | _ANDROIDAPPDELIVERYDATA = _descriptor.Descriptor( 501 | name='AndroidAppDeliveryData', 502 | full_name='AndroidAppDeliveryData', 503 | filename=None, 504 | file=DESCRIPTOR, 505 | containing_type=None, 506 | fields=[ 507 | _descriptor.FieldDescriptor( 508 | name='downloadUrl', full_name='AndroidAppDeliveryData.downloadUrl', index=0, 509 | number=3, type=9, cpp_type=9, label=1, 510 | has_default_value=False, default_value=_b("").decode('utf-8'), 511 | message_type=None, enum_type=None, containing_type=None, 512 | is_extension=False, extension_scope=None, 513 | options=None), 514 | _descriptor.FieldDescriptor( 515 | name='downloadAuthCookie', full_name='AndroidAppDeliveryData.downloadAuthCookie', index=1, 516 | number=5, type=11, cpp_type=10, label=3, 517 | has_default_value=False, default_value=[], 518 | message_type=None, enum_type=None, containing_type=None, 519 | is_extension=False, extension_scope=None, 520 | options=None), 521 | ], 522 | extensions=[ 523 | ], 524 | nested_types=[], 525 | enum_types=[ 526 | ], 527 | options=None, 528 | is_extendable=False, 529 | syntax='proto2', 530 | extension_ranges=[], 531 | oneofs=[ 532 | ], 533 | serialized_start=1166, 534 | serialized_end=1252, 535 | ) 536 | 537 | 538 | _HTTPCOOKIE = _descriptor.Descriptor( 539 | name='HttpCookie', 540 | full_name='HttpCookie', 541 | filename=None, 542 | file=DESCRIPTOR, 543 | containing_type=None, 544 | fields=[ 545 | _descriptor.FieldDescriptor( 546 | name='name', full_name='HttpCookie.name', index=0, 547 | number=1, type=9, cpp_type=9, label=1, 548 | has_default_value=False, default_value=_b("").decode('utf-8'), 549 | message_type=None, enum_type=None, containing_type=None, 550 | is_extension=False, extension_scope=None, 551 | options=None), 552 | _descriptor.FieldDescriptor( 553 | name='value', full_name='HttpCookie.value', index=1, 554 | number=2, type=9, cpp_type=9, label=1, 555 | has_default_value=False, default_value=_b("").decode('utf-8'), 556 | message_type=None, enum_type=None, containing_type=None, 557 | is_extension=False, extension_scope=None, 558 | options=None), 559 | ], 560 | extensions=[ 561 | ], 562 | nested_types=[], 563 | enum_types=[ 564 | ], 565 | options=None, 566 | is_extendable=False, 567 | syntax='proto2', 568 | extension_ranges=[], 569 | oneofs=[ 570 | ], 571 | serialized_start=1254, 572 | serialized_end=1295, 573 | ) 574 | 575 | 576 | _DETAILSRESPONSE = _descriptor.Descriptor( 577 | name='DetailsResponse', 578 | full_name='DetailsResponse', 579 | filename=None, 580 | file=DESCRIPTOR, 581 | containing_type=None, 582 | fields=[ 583 | _descriptor.FieldDescriptor( 584 | name='docV2', full_name='DetailsResponse.docV2', index=0, 585 | number=4, type=11, cpp_type=10, label=1, 586 | has_default_value=False, default_value=None, 587 | message_type=None, enum_type=None, containing_type=None, 588 | is_extension=False, extension_scope=None, 589 | options=None), 590 | ], 591 | extensions=[ 592 | ], 593 | nested_types=[], 594 | enum_types=[ 595 | ], 596 | options=None, 597 | is_extendable=False, 598 | syntax='proto2', 599 | extension_ranges=[], 600 | oneofs=[ 601 | ], 602 | serialized_start=1297, 603 | serialized_end=1337, 604 | ) 605 | 606 | 607 | _DOCV2 = _descriptor.Descriptor( 608 | name='DocV2', 609 | full_name='DocV2', 610 | filename=None, 611 | file=DESCRIPTOR, 612 | containing_type=None, 613 | fields=[ 614 | _descriptor.FieldDescriptor( 615 | name='details', full_name='DocV2.details', index=0, 616 | number=13, type=11, cpp_type=10, label=1, 617 | has_default_value=False, default_value=None, 618 | message_type=None, enum_type=None, containing_type=None, 619 | is_extension=False, extension_scope=None, 620 | options=None), 621 | ], 622 | extensions=[ 623 | ], 624 | nested_types=[], 625 | enum_types=[ 626 | ], 627 | options=None, 628 | is_extendable=False, 629 | syntax='proto2', 630 | extension_ranges=[], 631 | oneofs=[ 632 | ], 633 | serialized_start=1339, 634 | serialized_end=1381, 635 | ) 636 | 637 | 638 | _DOCUMENTDETAILS = _descriptor.Descriptor( 639 | name='DocumentDetails', 640 | full_name='DocumentDetails', 641 | filename=None, 642 | file=DESCRIPTOR, 643 | containing_type=None, 644 | fields=[ 645 | _descriptor.FieldDescriptor( 646 | name='appDetails', full_name='DocumentDetails.appDetails', index=0, 647 | number=1, type=11, cpp_type=10, label=1, 648 | has_default_value=False, default_value=None, 649 | message_type=None, enum_type=None, containing_type=None, 650 | is_extension=False, extension_scope=None, 651 | options=None), 652 | ], 653 | extensions=[ 654 | ], 655 | nested_types=[], 656 | enum_types=[ 657 | ], 658 | options=None, 659 | is_extendable=False, 660 | syntax='proto2', 661 | extension_ranges=[], 662 | oneofs=[ 663 | ], 664 | serialized_start=1383, 665 | serialized_end=1433, 666 | ) 667 | 668 | 669 | _APPDETAILS = _descriptor.Descriptor( 670 | name='AppDetails', 671 | full_name='AppDetails', 672 | filename=None, 673 | file=DESCRIPTOR, 674 | containing_type=None, 675 | fields=[ 676 | _descriptor.FieldDescriptor( 677 | name='versionCode', full_name='AppDetails.versionCode', index=0, 678 | number=3, type=5, cpp_type=1, label=1, 679 | has_default_value=False, default_value=0, 680 | message_type=None, enum_type=None, containing_type=None, 681 | is_extension=False, extension_scope=None, 682 | options=None), 683 | ], 684 | extensions=[ 685 | ], 686 | nested_types=[], 687 | enum_types=[ 688 | ], 689 | options=None, 690 | is_extendable=False, 691 | syntax='proto2', 692 | extension_ranges=[], 693 | oneofs=[ 694 | ], 695 | serialized_start=1435, 696 | serialized_end=1468, 697 | ) 698 | 699 | 700 | _DELIVERYRESPONSE = _descriptor.Descriptor( 701 | name='DeliveryResponse', 702 | full_name='DeliveryResponse', 703 | filename=None, 704 | file=DESCRIPTOR, 705 | containing_type=None, 706 | fields=[ 707 | _descriptor.FieldDescriptor( 708 | name='status', full_name='DeliveryResponse.status', index=0, 709 | number=1, type=5, cpp_type=1, label=1, 710 | has_default_value=False, default_value=0, 711 | message_type=None, enum_type=None, containing_type=None, 712 | is_extension=False, extension_scope=None, 713 | options=None), 714 | _descriptor.FieldDescriptor( 715 | name='appDeliveryData', full_name='DeliveryResponse.appDeliveryData', index=1, 716 | number=2, type=11, cpp_type=10, label=1, 717 | has_default_value=False, default_value=None, 718 | message_type=None, enum_type=None, containing_type=None, 719 | is_extension=False, extension_scope=None, 720 | options=None), 721 | ], 722 | extensions=[ 723 | ], 724 | nested_types=[], 725 | enum_types=[ 726 | ], 727 | options=None, 728 | is_extendable=False, 729 | syntax='proto2', 730 | extension_ranges=[], 731 | oneofs=[ 732 | ], 733 | serialized_start=1470, 734 | serialized_end=1554, 735 | ) 736 | 737 | _ANDROIDCHECKINREQUEST.fields_by_name['checkin'].message_type = _ANDROIDCHECKINPROTO 738 | _ANDROIDCHECKINREQUEST.fields_by_name['deviceConfiguration'].message_type = _DEVICECONFIGURATIONPROTO 739 | _ANDROIDCHECKINPROTO.fields_by_name['build'].message_type = _ANDROIDBUILDPROTO 740 | _RESPONSEWRAPPER.fields_by_name['payload'].message_type = _PAYLOAD 741 | _RESPONSEWRAPPER.fields_by_name['commands'].message_type = _SERVERCOMMANDS 742 | _PAYLOAD.fields_by_name['detailsResponse'].message_type = _DETAILSRESPONSE 743 | _PAYLOAD.fields_by_name['buyResponse'].message_type = _BUYRESPONSE 744 | _PAYLOAD.fields_by_name['deliveryResponse'].message_type = _DELIVERYRESPONSE 745 | _BUYRESPONSE.fields_by_name['purchaseStatusResponse'].message_type = _PURCHASESTATUSRESPONSE 746 | _PURCHASESTATUSRESPONSE.fields_by_name['appDeliveryData'].message_type = _ANDROIDAPPDELIVERYDATA 747 | _ANDROIDAPPDELIVERYDATA.fields_by_name['downloadAuthCookie'].message_type = _HTTPCOOKIE 748 | _DETAILSRESPONSE.fields_by_name['docV2'].message_type = _DOCV2 749 | _DOCV2.fields_by_name['details'].message_type = _DOCUMENTDETAILS 750 | _DOCUMENTDETAILS.fields_by_name['appDetails'].message_type = _APPDETAILS 751 | _DELIVERYRESPONSE.fields_by_name['appDeliveryData'].message_type = _ANDROIDAPPDELIVERYDATA 752 | DESCRIPTOR.message_types_by_name['AndroidCheckinRequest'] = _ANDROIDCHECKINREQUEST 753 | DESCRIPTOR.message_types_by_name['AndroidCheckinProto'] = _ANDROIDCHECKINPROTO 754 | DESCRIPTOR.message_types_by_name['AndroidBuildProto'] = _ANDROIDBUILDPROTO 755 | DESCRIPTOR.message_types_by_name['DeviceConfigurationProto'] = _DEVICECONFIGURATIONPROTO 756 | DESCRIPTOR.message_types_by_name['AndroidCheckinResponse'] = _ANDROIDCHECKINRESPONSE 757 | DESCRIPTOR.message_types_by_name['ResponseWrapper'] = _RESPONSEWRAPPER 758 | DESCRIPTOR.message_types_by_name['ServerCommands'] = _SERVERCOMMANDS 759 | DESCRIPTOR.message_types_by_name['Payload'] = _PAYLOAD 760 | DESCRIPTOR.message_types_by_name['BuyResponse'] = _BUYRESPONSE 761 | DESCRIPTOR.message_types_by_name['PurchaseStatusResponse'] = _PURCHASESTATUSRESPONSE 762 | DESCRIPTOR.message_types_by_name['AndroidAppDeliveryData'] = _ANDROIDAPPDELIVERYDATA 763 | DESCRIPTOR.message_types_by_name['HttpCookie'] = _HTTPCOOKIE 764 | DESCRIPTOR.message_types_by_name['DetailsResponse'] = _DETAILSRESPONSE 765 | DESCRIPTOR.message_types_by_name['DocV2'] = _DOCV2 766 | DESCRIPTOR.message_types_by_name['DocumentDetails'] = _DOCUMENTDETAILS 767 | DESCRIPTOR.message_types_by_name['AppDetails'] = _APPDETAILS 768 | DESCRIPTOR.message_types_by_name['DeliveryResponse'] = _DELIVERYRESPONSE 769 | 770 | AndroidCheckinRequest = _reflection.GeneratedProtocolMessageType('AndroidCheckinRequest', (_message.Message,), dict( 771 | DESCRIPTOR = _ANDROIDCHECKINREQUEST, 772 | __module__ = 'apkfetch_pb2' 773 | # @@protoc_insertion_point(class_scope:AndroidCheckinRequest) 774 | )) 775 | _sym_db.RegisterMessage(AndroidCheckinRequest) 776 | 777 | AndroidCheckinProto = _reflection.GeneratedProtocolMessageType('AndroidCheckinProto', (_message.Message,), dict( 778 | DESCRIPTOR = _ANDROIDCHECKINPROTO, 779 | __module__ = 'apkfetch_pb2' 780 | # @@protoc_insertion_point(class_scope:AndroidCheckinProto) 781 | )) 782 | _sym_db.RegisterMessage(AndroidCheckinProto) 783 | 784 | AndroidBuildProto = _reflection.GeneratedProtocolMessageType('AndroidBuildProto', (_message.Message,), dict( 785 | DESCRIPTOR = _ANDROIDBUILDPROTO, 786 | __module__ = 'apkfetch_pb2' 787 | # @@protoc_insertion_point(class_scope:AndroidBuildProto) 788 | )) 789 | _sym_db.RegisterMessage(AndroidBuildProto) 790 | 791 | DeviceConfigurationProto = _reflection.GeneratedProtocolMessageType('DeviceConfigurationProto', (_message.Message,), dict( 792 | DESCRIPTOR = _DEVICECONFIGURATIONPROTO, 793 | __module__ = 'apkfetch_pb2' 794 | # @@protoc_insertion_point(class_scope:DeviceConfigurationProto) 795 | )) 796 | _sym_db.RegisterMessage(DeviceConfigurationProto) 797 | 798 | AndroidCheckinResponse = _reflection.GeneratedProtocolMessageType('AndroidCheckinResponse', (_message.Message,), dict( 799 | DESCRIPTOR = _ANDROIDCHECKINRESPONSE, 800 | __module__ = 'apkfetch_pb2' 801 | # @@protoc_insertion_point(class_scope:AndroidCheckinResponse) 802 | )) 803 | _sym_db.RegisterMessage(AndroidCheckinResponse) 804 | 805 | ResponseWrapper = _reflection.GeneratedProtocolMessageType('ResponseWrapper', (_message.Message,), dict( 806 | DESCRIPTOR = _RESPONSEWRAPPER, 807 | __module__ = 'apkfetch_pb2' 808 | # @@protoc_insertion_point(class_scope:ResponseWrapper) 809 | )) 810 | _sym_db.RegisterMessage(ResponseWrapper) 811 | 812 | ServerCommands = _reflection.GeneratedProtocolMessageType('ServerCommands', (_message.Message,), dict( 813 | DESCRIPTOR = _SERVERCOMMANDS, 814 | __module__ = 'apkfetch_pb2' 815 | # @@protoc_insertion_point(class_scope:ServerCommands) 816 | )) 817 | _sym_db.RegisterMessage(ServerCommands) 818 | 819 | Payload = _reflection.GeneratedProtocolMessageType('Payload', (_message.Message,), dict( 820 | DESCRIPTOR = _PAYLOAD, 821 | __module__ = 'apkfetch_pb2' 822 | # @@protoc_insertion_point(class_scope:Payload) 823 | )) 824 | _sym_db.RegisterMessage(Payload) 825 | 826 | BuyResponse = _reflection.GeneratedProtocolMessageType('BuyResponse', (_message.Message,), dict( 827 | DESCRIPTOR = _BUYRESPONSE, 828 | __module__ = 'apkfetch_pb2' 829 | # @@protoc_insertion_point(class_scope:BuyResponse) 830 | )) 831 | _sym_db.RegisterMessage(BuyResponse) 832 | 833 | PurchaseStatusResponse = _reflection.GeneratedProtocolMessageType('PurchaseStatusResponse', (_message.Message,), dict( 834 | DESCRIPTOR = _PURCHASESTATUSRESPONSE, 835 | __module__ = 'apkfetch_pb2' 836 | # @@protoc_insertion_point(class_scope:PurchaseStatusResponse) 837 | )) 838 | _sym_db.RegisterMessage(PurchaseStatusResponse) 839 | 840 | AndroidAppDeliveryData = _reflection.GeneratedProtocolMessageType('AndroidAppDeliveryData', (_message.Message,), dict( 841 | DESCRIPTOR = _ANDROIDAPPDELIVERYDATA, 842 | __module__ = 'apkfetch_pb2' 843 | # @@protoc_insertion_point(class_scope:AndroidAppDeliveryData) 844 | )) 845 | _sym_db.RegisterMessage(AndroidAppDeliveryData) 846 | 847 | HttpCookie = _reflection.GeneratedProtocolMessageType('HttpCookie', (_message.Message,), dict( 848 | DESCRIPTOR = _HTTPCOOKIE, 849 | __module__ = 'apkfetch_pb2' 850 | # @@protoc_insertion_point(class_scope:HttpCookie) 851 | )) 852 | _sym_db.RegisterMessage(HttpCookie) 853 | 854 | DetailsResponse = _reflection.GeneratedProtocolMessageType('DetailsResponse', (_message.Message,), dict( 855 | DESCRIPTOR = _DETAILSRESPONSE, 856 | __module__ = 'apkfetch_pb2' 857 | # @@protoc_insertion_point(class_scope:DetailsResponse) 858 | )) 859 | _sym_db.RegisterMessage(DetailsResponse) 860 | 861 | DocV2 = _reflection.GeneratedProtocolMessageType('DocV2', (_message.Message,), dict( 862 | DESCRIPTOR = _DOCV2, 863 | __module__ = 'apkfetch_pb2' 864 | # @@protoc_insertion_point(class_scope:DocV2) 865 | )) 866 | _sym_db.RegisterMessage(DocV2) 867 | 868 | DocumentDetails = _reflection.GeneratedProtocolMessageType('DocumentDetails', (_message.Message,), dict( 869 | DESCRIPTOR = _DOCUMENTDETAILS, 870 | __module__ = 'apkfetch_pb2' 871 | # @@protoc_insertion_point(class_scope:DocumentDetails) 872 | )) 873 | _sym_db.RegisterMessage(DocumentDetails) 874 | 875 | AppDetails = _reflection.GeneratedProtocolMessageType('AppDetails', (_message.Message,), dict( 876 | DESCRIPTOR = _APPDETAILS, 877 | __module__ = 'apkfetch_pb2' 878 | # @@protoc_insertion_point(class_scope:AppDetails) 879 | )) 880 | _sym_db.RegisterMessage(AppDetails) 881 | 882 | DeliveryResponse = _reflection.GeneratedProtocolMessageType('DeliveryResponse', (_message.Message,), dict( 883 | DESCRIPTOR = _DELIVERYRESPONSE, 884 | __module__ = 'apkfetch_pb2' 885 | # @@protoc_insertion_point(class_scope:DeliveryResponse) 886 | )) 887 | _sym_db.RegisterMessage(DeliveryResponse) 888 | 889 | 890 | # @@protoc_insertion_point(module_scope) 891 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | protobuf 3 | pycryptodome -------------------------------------------------------------------------------- /util.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import base64 3 | import binascii 4 | import hashlib 5 | 6 | from struct import unpack_from 7 | 8 | from Crypto.Cipher import PKCS1_OAEP 9 | from Crypto.PublicKey import RSA 10 | 11 | if sys.version_info[0] == 3: 12 | long = int 13 | 14 | GOOGLE_PUBLIC_KEY = 'AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3iJIZdodyhKZQrNWp5nKJ3srRXcUW+F1BD3baEVGcmEgqaLZUNBjm057pKRI16kB0YppeGx5qIQ5QjKzsR8ETQbKLNWgRY0QRNVz34kMJR3P/LgHax/6rmf5AAAAAwEAAQ==' 15 | 16 | 17 | def encrypt(username, password): 18 | public_key = base64.b64decode(GOOGLE_PUBLIC_KEY) 19 | 20 | modulus_length = read_length(public_key, 0) 21 | modulus_data = public_key[4:4+modulus_length] 22 | modulus = long(binascii.hexlify(modulus_data), 16) 23 | 24 | exponent_length = read_length(public_key, 4+modulus_length) 25 | exponent_data = public_key[8+modulus_length:8+modulus_length+exponent_length] 26 | exponent = long(binascii.hexlify(exponent_data), 16) 27 | 28 | signature = b'\x00' + hashlib.sha1(public_key).digest()[:4] 29 | 30 | key = RSA.construct((modulus, exponent)) 31 | cipher = PKCS1_OAEP.new(key) 32 | plaintext = username.encode('utf-8') + b'\x00' + password.encode('utf-8') 33 | ciphertext = cipher.encrypt(plaintext) 34 | 35 | result = signature + ciphertext 36 | return base64.urlsafe_b64encode(result) 37 | 38 | 39 | def read_length(bin, offset): 40 | return (0xff & ord(bin[offset:offset+1])) << 24 \ 41 | | (0xff & ord(bin[offset+1:offset+2])) << 16 \ 42 | | (0xff & ord(bin[offset+2:offset+3])) << 8 \ 43 | | (0xff & ord(bin[offset+3:offset+4])) << 0 44 | --------------------------------------------------------------------------------