2017-09-21 09:19:48 +00:00
|
|
|
from . import googleplay_pb2
|
2017-10-30 16:30:10 +00:00
|
|
|
from time import time
|
|
|
|
from os import path
|
|
|
|
from sys import version_info
|
2017-11-13 10:44:15 +00:00
|
|
|
from re import match
|
2017-10-04 11:42:52 +00:00
|
|
|
|
2017-10-30 16:30:10 +00:00
|
|
|
VERSION = version_info[0]
|
2017-10-04 11:42:52 +00:00
|
|
|
if VERSION == 2:
|
|
|
|
import ConfigParser
|
|
|
|
else:
|
|
|
|
import configparser
|
2017-09-15 20:11:44 +00:00
|
|
|
|
2017-08-27 15:32:05 +00:00
|
|
|
|
2017-10-12 17:46:20 +00:00
|
|
|
DFE_TARGETS = "CAEScFfqlIEG6gUYogFWrAISK1WDAg+hAZoCDgIU1gYEOIACFkLMAeQBnASLATlASUuyAyqCAjY5igOMBQzfA/IClwFbApUC4ANbtgKVAS7OAX8YswHFBhgDwAOPAmGEBt4OfKkB5weSB5AFASkiN68akgMaxAMSAQEBA9kBO7UBFE1KVwIDBGs3go6BBgEBAgMECQgJAQIEAQMEAQMBBQEBBAUEFQYCBgUEAwMBDwIBAgOrARwBEwMEAg0mrwESfTEcAQEKG4EBMxghChMBDwYGASI3hAEODEwXCVh/EREZA4sBYwEdFAgIIwkQcGQRDzQ2fTC2AjfVAQIBAYoBGRg2FhYFBwEqNzACJShzFFblAo0CFxpFNBzaAd0DHjIRI4sBJZcBPdwBCQGhAUd2A7kBLBVPngEECHl0UEUMtQETigHMAgUFCc0BBUUlTywdHDgBiAJ+vgKhAU0uAcYCAWQ/5ALUAw1UwQHUBpIBCdQDhgL4AY4CBQICjARbGFBGWzA1CAEMOQH+BRAOCAZywAIDyQZ2MgM3BxsoAgUEBwcHFia3AgcGTBwHBYwBAlcBggFxSGgIrAEEBw4QEqUCASsWadsHCgUCBQMD7QICA3tXCUw7ugJZAwGyAUwpIwM5AwkDBQMJA5sBCw8BNxBVVBwVKhebARkBAwsQEAgEAhESAgQJEBCZATMdzgEBBwG8AQQYKSMUkAEDAwY/CTs4/wEaAUt1AwEDAQUBAgIEAwYEDx1dB2wGeBFgTQ"
|
2017-10-10 16:35:40 +00:00
|
|
|
GOOGLE_PUBKEY = "AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3iJIZdodyhKZQrNWp5nKJ3srRXcUW+F1BD3baEVGcmEgqaLZUNBjm057pKRI16kB0YppeGx5qIQ5QjKzsR8ETQbKLNWgRY0QRNVz34kMJR3P/LgHax/6rmf5AAAAAwEAAQ=="
|
2017-10-19 15:51:03 +00:00
|
|
|
ACCOUNT = "HOSTED_OR_GOOGLE"
|
2017-08-27 15:32:05 +00:00
|
|
|
|
2017-09-18 14:06:57 +00:00
|
|
|
# parse phone config from the file 'device.properties'.
|
|
|
|
# if you want to add another phone, just create another section in
|
|
|
|
# the file. Some configurations for common phones can be found here:
|
|
|
|
# https://github.com/yeriomin/play-store-api/tree/master/src/main/resources
|
2017-10-30 16:30:10 +00:00
|
|
|
filepath = path.join(path.dirname(path.realpath(__file__)),
|
|
|
|
'device.properties')
|
2017-10-13 17:12:06 +00:00
|
|
|
|
2017-10-04 11:42:52 +00:00
|
|
|
if VERSION == 2:
|
|
|
|
config = ConfigParser.ConfigParser()
|
|
|
|
else:
|
|
|
|
config = configparser.ConfigParser()
|
2017-09-16 17:12:06 +00:00
|
|
|
config.read(filepath)
|
2017-10-09 19:34:40 +00:00
|
|
|
|
2017-10-10 16:35:40 +00:00
|
|
|
|
2017-10-09 19:34:40 +00:00
|
|
|
def getDevicesCodenames():
|
2017-10-10 17:18:20 +00:00
|
|
|
"""Returns a list containing devices codenames"""
|
2017-10-09 19:34:40 +00:00
|
|
|
return config.sections()
|
2017-09-15 20:11:44 +00:00
|
|
|
|
2017-10-10 16:35:40 +00:00
|
|
|
|
2017-10-10 17:18:20 +00:00
|
|
|
def getDevicesReadableNames():
|
2017-10-10 17:23:58 +00:00
|
|
|
"""Returns codename and readable name for each device"""
|
2018-01-25 10:36:25 +00:00
|
|
|
return [{'codename': s,
|
|
|
|
'readableName': config.get(s).get('userreadablename')}
|
|
|
|
for s in getDevicesCodenames()]
|
2017-10-10 17:18:20 +00:00
|
|
|
|
|
|
|
|
2017-10-13 17:12:06 +00:00
|
|
|
class DeviceBuilder(object):
|
|
|
|
|
|
|
|
def __init__(self, device):
|
|
|
|
self.device = {}
|
|
|
|
for (key, value) in config.items(device):
|
|
|
|
self.device[key] = value
|
|
|
|
|
2018-01-27 18:42:36 +00:00
|
|
|
def set_locale(self, locale):
|
2017-11-14 10:22:19 +00:00
|
|
|
# test if provided locale is valid
|
|
|
|
if locale is None or type(locale) is not str:
|
2018-01-25 10:36:25 +00:00
|
|
|
raise Exception('Wrong locale supplied')
|
2017-11-13 10:44:15 +00:00
|
|
|
|
|
|
|
# check if locale matches the structure of a common
|
|
|
|
# value like "en_US"
|
|
|
|
if match(r'[a-z]{2}\_[A-Z]{2}', locale) is None:
|
2018-01-25 10:36:25 +00:00
|
|
|
raise Exception('Wrong locale supplied')
|
2017-11-13 10:44:15 +00:00
|
|
|
self.locale = locale
|
|
|
|
|
2018-01-25 10:36:25 +00:00
|
|
|
def set_timezone(self, timezone):
|
|
|
|
if timezone is None or type(timezone) is not str:
|
|
|
|
timezone = self.device.get('timezone')
|
|
|
|
if timezone is None:
|
|
|
|
raise Exception('Wrong timezone supplied')
|
|
|
|
self.timezone = timezone
|
|
|
|
|
2017-10-13 17:12:06 +00:00
|
|
|
def getUserAgent(self):
|
2018-01-25 10:36:25 +00:00
|
|
|
version_string = self.device.get('vending.versionstring')
|
|
|
|
if version_string is None:
|
|
|
|
version_string = '8.4.19.V-all [0] [FP] 175058788'
|
|
|
|
return ("Android-Finsky/{versionString} ("
|
2017-10-13 17:12:06 +00:00
|
|
|
"api=3"
|
|
|
|
",versionCode={versionCode}"
|
|
|
|
",sdk={sdk}"
|
|
|
|
",device={device}"
|
|
|
|
",hardware={hardware}"
|
|
|
|
",product={product}"
|
2018-01-26 17:24:19 +00:00
|
|
|
",platformVersionRelease={platform_v}"
|
|
|
|
",model={model}"
|
|
|
|
",buildId={build_id}"
|
|
|
|
",isWideScreen=0"
|
|
|
|
",supportedAbis={supported_abis}"
|
|
|
|
")").format(versionString=version_string,
|
|
|
|
versionCode=self.device.get('vending.version'),
|
|
|
|
sdk=self.device.get('build.version.sdk_int'),
|
|
|
|
device=self.device.get('build.device'),
|
|
|
|
hardware=self.device.get('build.hardware'),
|
|
|
|
product=self.device.get('build.product'),
|
|
|
|
platform_v=self.device.get('build.version.release'),
|
|
|
|
model=self.device.get('build.model'),
|
|
|
|
build_id=self.device.get('build.id'),
|
2018-01-26 18:46:23 +00:00
|
|
|
supported_abis=self.device.get('platforms').replace(',', ';'))
|
|
|
|
|
|
|
|
def getAuthHeaders(self, gsfid):
|
|
|
|
headers = {"User-Agent": ("GoogleAuth/1.4 ("
|
|
|
|
"{device} {id}"
|
|
|
|
")").format(device=self.device.get('build.device'),
|
|
|
|
id=self.device.get('build.id'))}
|
|
|
|
if gsfid is not None:
|
|
|
|
headers['device'] = "{0:x}".format(gsfid)
|
|
|
|
return headers
|
2017-10-13 17:12:06 +00:00
|
|
|
|
2018-01-26 18:46:23 +00:00
|
|
|
def getLoginParams(self, email, encrypted_passwd):
|
2017-10-19 15:51:03 +00:00
|
|
|
return {"Email": email,
|
2018-01-26 18:46:23 +00:00
|
|
|
"EncryptedPasswd": encrypted_passwd,
|
2017-10-19 15:51:03 +00:00
|
|
|
"add_account": "1",
|
|
|
|
"accountType": ACCOUNT,
|
2018-01-26 19:15:54 +00:00
|
|
|
"google_play_services_version": self.device.get('gsf.version'),
|
2017-10-19 15:51:03 +00:00
|
|
|
"has_permission": "1",
|
|
|
|
"source": "android",
|
2017-10-30 16:30:10 +00:00
|
|
|
"device_country": self.locale[0:2],
|
|
|
|
"lang": self.locale,
|
2018-01-26 19:15:54 +00:00
|
|
|
"sdk_version": self.device.get('build.version.sdk_int'),
|
|
|
|
"client_sig": "38918a453d07199354f8b19af05ec6562ced5788",
|
|
|
|
"callerSig": "38918a453d07199354f8b19af05ec6562ced5788"}
|
2017-10-19 15:51:03 +00:00
|
|
|
|
2017-10-13 17:12:06 +00:00
|
|
|
def getAndroidCheckinRequest(self):
|
|
|
|
request = googleplay_pb2.AndroidCheckinRequest()
|
|
|
|
request.id = 0
|
|
|
|
request.checkin.CopyFrom(self.getAndroidCheckin())
|
2017-10-30 16:30:10 +00:00
|
|
|
request.locale = self.locale
|
|
|
|
request.timeZone = self.timezone
|
2017-10-13 17:12:06 +00:00
|
|
|
request.version = 3
|
|
|
|
request.deviceConfiguration.CopyFrom(self.getDeviceConfig())
|
|
|
|
request.fragment = 0
|
|
|
|
return request
|
|
|
|
|
|
|
|
def getDeviceConfig(self):
|
|
|
|
libList = self.device['sharedlibraries'].split(",")
|
|
|
|
featureList = self.device['features'].split(",")
|
|
|
|
localeList = self.device['locales'].split(",")
|
|
|
|
glList = self.device['gl.extensions'].split(",")
|
|
|
|
platforms = self.device['platforms'].split(",")
|
|
|
|
|
|
|
|
hasFiveWayNavigation = (self.device['hasfivewaynavigation'] == 'true')
|
|
|
|
hasHardKeyboard = (self.device['hashardkeyboard'] == 'true')
|
|
|
|
deviceConfig = googleplay_pb2.DeviceConfigurationProto()
|
|
|
|
deviceConfig.touchScreen = int(self.device['touchscreen'])
|
|
|
|
deviceConfig.keyboard = int(self.device['keyboard'])
|
|
|
|
deviceConfig.navigation = int(self.device['navigation'])
|
|
|
|
deviceConfig.screenLayout = int(self.device['screenlayout'])
|
|
|
|
deviceConfig.hasHardKeyboard = hasHardKeyboard
|
|
|
|
deviceConfig.hasFiveWayNavigation = hasFiveWayNavigation
|
|
|
|
deviceConfig.screenDensity = int(self.device['screen.density'])
|
|
|
|
deviceConfig.screenWidth = int(self.device['screen.width'])
|
|
|
|
deviceConfig.screenHeight = int(self.device['screen.height'])
|
|
|
|
deviceConfig.glEsVersion = int(self.device['gl.version'])
|
|
|
|
for x in platforms:
|
|
|
|
deviceConfig.nativePlatform.append(x)
|
|
|
|
for x in libList:
|
|
|
|
deviceConfig.systemSharedLibrary.append(x)
|
|
|
|
for x in featureList:
|
|
|
|
deviceConfig.systemAvailableFeature.append(x)
|
|
|
|
for x in localeList:
|
|
|
|
deviceConfig.systemSupportedLocale.append(x)
|
|
|
|
for x in glList:
|
|
|
|
deviceConfig.glExtension.append(x)
|
|
|
|
return deviceConfig
|
|
|
|
|
|
|
|
def getAndroidBuild(self):
|
|
|
|
androidBuild = googleplay_pb2.AndroidBuildProto()
|
|
|
|
androidBuild.id = self.device['build.fingerprint']
|
|
|
|
androidBuild.product = self.device['build.hardware']
|
|
|
|
androidBuild.carrier = self.device['build.brand']
|
|
|
|
androidBuild.radio = self.device['build.radio']
|
|
|
|
androidBuild.bootloader = self.device['build.bootloader']
|
|
|
|
androidBuild.device = self.device['build.device']
|
|
|
|
androidBuild.sdkVersion = int(self.device['build.version.sdk_int'])
|
|
|
|
androidBuild.model = self.device['build.model']
|
|
|
|
androidBuild.manufacturer = self.device['build.manufacturer']
|
|
|
|
androidBuild.buildProduct = self.device['build.product']
|
|
|
|
androidBuild.client = self.device['client']
|
|
|
|
androidBuild.otaInstalled = False
|
2017-11-10 21:12:34 +00:00
|
|
|
androidBuild.timestamp = int(time()/1000)
|
2017-10-13 17:12:06 +00:00
|
|
|
androidBuild.googleServices = int(self.device['gsf.version'])
|
|
|
|
return androidBuild
|
|
|
|
|
|
|
|
def getAndroidCheckin(self):
|
|
|
|
androidCheckin = googleplay_pb2.AndroidCheckinProto()
|
|
|
|
androidCheckin.build.CopyFrom(self.getAndroidBuild())
|
|
|
|
androidCheckin.lastCheckinMsec = 0
|
|
|
|
androidCheckin.cellOperator = self.device['celloperator']
|
|
|
|
androidCheckin.simOperator = self.device['simoperator']
|
|
|
|
androidCheckin.roaming = self.device['roaming']
|
|
|
|
androidCheckin.userNumber = 0
|
|
|
|
return androidCheckin
|