Signed-off-by: Domenico Iezzi <domenico.iezzi.201@gmail.com>
This commit is contained in:
Domenico Iezzi 2017-10-13 19:12:06 +02:00
parent 2ab7ce09c6
commit 9d0d14450b
2 changed files with 98 additions and 99 deletions

View File

@ -19,20 +19,14 @@ GOOGLE_PUBKEY = "AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3iJIZdo
# if you want to add another phone, just create another section in # if you want to add another phone, just create another section in
# the file. Some configurations for common phones can be found here: # the file. Some configurations for common phones can be found here:
# https://github.com/yeriomin/play-store-api/tree/master/src/main/resources # https://github.com/yeriomin/play-store-api/tree/master/src/main/resources
filepath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'device.properties')
if VERSION == 2: if VERSION == 2:
config = ConfigParser.ConfigParser() config = ConfigParser.ConfigParser()
else: else:
config = configparser.ConfigParser() config = configparser.ConfigParser()
filepath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'device.properties')
config.read(filepath) config.read(filepath)
device = {}
# initialize device, because we need to setup UserAgent
# before the end of login method. If the login defines a different
# device, it won't cause conflicts
for (key, value) in config.items('angler'):
device[key] = value
def getDevicesCodenames(): def getDevicesCodenames():
@ -50,40 +44,58 @@ def getDevicesReadableNames():
return output return output
def getUserAgent(): class DeviceBuilder(object):
def __init__(self, device):
self.device = {}
for (key, value) in config.items(device):
self.device[key] = value
def getUserAgent(self):
return ("Android-Finsky/8.1.72.S-all [6] [PR] 165478484 (" return ("Android-Finsky/8.1.72.S-all [6] [PR] 165478484 ("
"api=3" "api=3"
",versionCode={versionCode}" ",versionCode={versionCode}"
",sdk={sdk}" ",sdk={sdk}"
",device={device}" ",device={device}"
",hardware={hardware}" ",hardware={hardware}"
",product={product}").format(versionCode=device['vending.version'], ",product={product}"
sdk=device['build.version.sdk_int'], "").format(versionCode=self.device['vending.version'],
device=device['build.device'], sdk=self.device['build.version.sdk_int'],
hardware=device['build.hardware'], device=self.device['build.device'],
product=device['build.product']) hardware=self.device['build.hardware'],
product=self.device['build.product'])
def getAndroidCheckinRequest(self):
request = googleplay_pb2.AndroidCheckinRequest()
request.id = 0
request.checkin.CopyFrom(self.getAndroidCheckin())
request.locale = LANG
request.timeZone = TIMEZONE
request.version = 3
request.deviceConfiguration.CopyFrom(self.getDeviceConfig())
request.fragment = 0
return request
def getDeviceConfig(): def getDeviceConfig(self):
libList = device['sharedlibraries'].split(",") libList = self.device['sharedlibraries'].split(",")
featureList = device['features'].split(",") featureList = self.device['features'].split(",")
localeList = device['locales'].split(",") localeList = self.device['locales'].split(",")
glList = device['gl.extensions'].split(",") glList = self.device['gl.extensions'].split(",")
platforms = device['platforms'].split(",") platforms = self.device['platforms'].split(",")
hasFiveWayNavigation = (device['hasfivewaynavigation'] == 'true') hasFiveWayNavigation = (self.device['hasfivewaynavigation'] == 'true')
hasHardKeyboard = (device['hashardkeyboard'] == 'true') hasHardKeyboard = (self.device['hashardkeyboard'] == 'true')
deviceConfig = googleplay_pb2.DeviceConfigurationProto() deviceConfig = googleplay_pb2.DeviceConfigurationProto()
deviceConfig.touchScreen = int(device['touchscreen']) deviceConfig.touchScreen = int(self.device['touchscreen'])
deviceConfig.keyboard = int(device['keyboard']) deviceConfig.keyboard = int(self.device['keyboard'])
deviceConfig.navigation = int(device['navigation']) deviceConfig.navigation = int(self.device['navigation'])
deviceConfig.screenLayout = int(device['screenlayout']) deviceConfig.screenLayout = int(self.device['screenlayout'])
deviceConfig.hasHardKeyboard = hasHardKeyboard deviceConfig.hasHardKeyboard = hasHardKeyboard
deviceConfig.hasFiveWayNavigation = hasFiveWayNavigation deviceConfig.hasFiveWayNavigation = hasFiveWayNavigation
deviceConfig.screenDensity = int(device['screen.density']) deviceConfig.screenDensity = int(self.device['screen.density'])
deviceConfig.screenWidth = int(device['screen.width']) deviceConfig.screenWidth = int(self.device['screen.width'])
deviceConfig.screenHeight = int(device['screen.height']) deviceConfig.screenHeight = int(self.device['screen.height'])
deviceConfig.glEsVersion = int(device['gl.version']) deviceConfig.glEsVersion = int(self.device['gl.version'])
for x in platforms: for x in platforms:
deviceConfig.nativePlatform.append(x) deviceConfig.nativePlatform.append(x)
for x in libList: for x in libList:
@ -96,46 +108,30 @@ def getDeviceConfig():
deviceConfig.glExtension.append(x) deviceConfig.glExtension.append(x)
return deviceConfig return deviceConfig
def getAndroidBuild(self):
def getAndroidBuild():
androidBuild = googleplay_pb2.AndroidBuildProto() androidBuild = googleplay_pb2.AndroidBuildProto()
androidBuild.id = device['build.fingerprint'] androidBuild.id = self.device['build.fingerprint']
androidBuild.product = device['build.hardware'] androidBuild.product = self.device['build.hardware']
androidBuild.carrier = device['build.brand'] androidBuild.carrier = self.device['build.brand']
androidBuild.radio = device['build.radio'] androidBuild.radio = self.device['build.radio']
androidBuild.bootloader = device['build.bootloader'] androidBuild.bootloader = self.device['build.bootloader']
androidBuild.device = device['build.device'] androidBuild.device = self.device['build.device']
androidBuild.sdkVersion = int(device['build.version.sdk_int']) androidBuild.sdkVersion = int(self.device['build.version.sdk_int'])
androidBuild.model = device['build.model'] androidBuild.model = self.device['build.model']
androidBuild.manufacturer = device['build.manufacturer'] androidBuild.manufacturer = self.device['build.manufacturer']
androidBuild.buildProduct = device['build.product'] androidBuild.buildProduct = self.device['build.product']
androidBuild.client = device['client'] androidBuild.client = self.device['client']
androidBuild.otaInstalled = False androidBuild.otaInstalled = False
androidBuild.timestamp = int(time.time()) androidBuild.timestamp = int(time.time())
androidBuild.googleServices = int(device['gsf.version']) androidBuild.googleServices = int(self.device['gsf.version'])
return androidBuild return androidBuild
def getAndroidCheckin(self):
def getAndroidCheckin():
androidCheckin = googleplay_pb2.AndroidCheckinProto() androidCheckin = googleplay_pb2.AndroidCheckinProto()
androidCheckin.build.CopyFrom(getAndroidBuild()) androidCheckin.build.CopyFrom(self.getAndroidBuild())
androidCheckin.lastCheckinMsec = 0 androidCheckin.lastCheckinMsec = 0
androidCheckin.cellOperator = device['celloperator'] androidCheckin.cellOperator = self.device['celloperator']
androidCheckin.simOperator = device['simoperator'] androidCheckin.simOperator = self.device['simoperator']
androidCheckin.roaming = device['roaming'] androidCheckin.roaming = self.device['roaming']
androidCheckin.userNumber = 0 androidCheckin.userNumber = 0
return androidCheckin return androidCheckin
def getAndroidCheckinRequest(device_codename):
for (key, value) in config.items(device_codename):
device[key] = value
request = googleplay_pb2.AndroidCheckinRequest()
request.id = 0
request.checkin.CopyFrom(getAndroidCheckin())
request.locale = LANG
request.timeZone = TIMEZONE
request.version = 3
request.deviceConfiguration.CopyFrom(getDeviceConfig())
request.fragment = 0
return request

View File

@ -46,11 +46,12 @@ class GooglePlayAPI(object):
AUTHURL = BASE + "auth" AUTHURL = BASE + "auth"
ACCOUNT = "HOSTED_OR_GOOGLE" ACCOUNT = "HOSTED_OR_GOOGLE"
def __init__(self, debug=False): def __init__(self, debug=False, device_codename='bacon'):
self.authSubToken = None self.authSubToken = None
self.gsfId = None self.gsfId = None
self.lang = config.LANG self.lang = config.LANG
self.debug = debug self.debug = debug
self.deviceBuilder = config.DeviceBuilder(device_codename)
def encrypt_password(self, login, passwd): def encrypt_password(self, login, passwd):
"""Encrypt the password using the google publickey, using """Encrypt the password using the google publickey, using
@ -87,7 +88,7 @@ class GooglePlayAPI(object):
headers = { headers = {
"Accept-Language": config.LANG.replace('_', '-'), "Accept-Language": config.LANG.replace('_', '-'),
"X-DFE-Encoded-Targets": config.DFE_TARGETS, "X-DFE-Encoded-Targets": config.DFE_TARGETS,
"User-Agent": config.getUserAgent() "User-Agent": self.deviceBuilder.getUserAgent()
} }
if self.gsfId is not None: if self.gsfId is not None:
headers["X-DFE-Device-Id"] = "{0:x}".format(self.gsfId) headers["X-DFE-Device-Id"] = "{0:x}".format(self.gsfId)
@ -95,11 +96,11 @@ class GooglePlayAPI(object):
headers["Authorization"] = "GoogleLogin auth=%s" % self.authSubToken headers["Authorization"] = "GoogleLogin auth=%s" % self.authSubToken
return headers return headers
def checkin(self, email, ac2dmToken, device_codename): def checkin(self, email, ac2dmToken):
headers = self.getDefaultHeaders() headers = self.getDefaultHeaders()
headers["Content-Type"] = "application/x-protobuffer" headers["Content-Type"] = "application/x-protobuffer"
request = config.getAndroidCheckinRequest(device_codename) request = self.deviceBuilder.getAndroidCheckinRequest()
stringRequest = request.SerializeToString() stringRequest = request.SerializeToString()
res = requests.post(self.CHECKINURL, data=stringRequest, res = requests.post(self.CHECKINURL, data=stringRequest,
@ -125,7 +126,7 @@ class GooglePlayAPI(object):
*device.properties* to the google account. Default device is a Google Nexus 6P""" *device.properties* to the google account. Default device is a Google Nexus 6P"""
upload = googleplay_pb2.UploadDeviceConfigRequest() upload = googleplay_pb2.UploadDeviceConfigRequest()
upload.deviceConfiguration.CopyFrom(config.getDeviceConfig()) upload.deviceConfiguration.CopyFrom(self.deviceBuilder.getDeviceConfig())
headers = self.getDefaultHeaders() headers = self.getDefaultHeaders()
headers["X-DFE-Enabled-Experiments"] = "cl:billing.select_add_instrument_by_default" headers["X-DFE-Enabled-Experiments"] = "cl:billing.select_add_instrument_by_default"
headers["X-DFE-Unsupported-Experiments"] = "nocache:billing.use_charging_poller,market_emails,buyer_currency,prod_baseline,checkin.set_asset_paid_app_field,shekel_test,content_ratings,buyer_currency_in_app,nocache:encrypted_apk,recent_changes" headers["X-DFE-Unsupported-Experiments"] = "nocache:billing.use_charging_poller,market_emails,buyer_currency,prod_baseline,checkin.set_asset_paid_app_field,shekel_test,content_ratings,buyer_currency_in_app,nocache:encrypted_apk,recent_changes"
@ -137,8 +138,7 @@ class GooglePlayAPI(object):
headers=headers, verify=ssl_verify) headers=headers, verify=ssl_verify)
googleplay_pb2.ResponseWrapper.FromString(res.content) googleplay_pb2.ResponseWrapper.FromString(res.content)
def login(self, email=None, password=None, gsfId=None, def login(self, email=None, password=None, gsfId=None, authSubToken=None):
authSubToken=None, device_codename='bacon'):
"""Login to your Google Account. """Login to your Google Account.
For first time login you should provide: For first time login you should provide:
* email * email
@ -185,7 +185,7 @@ class GooglePlayAPI(object):
else: else:
raise LoginError("Auth token not found.") raise LoginError("Auth token not found.")
self.gsfId = self.checkin(email, ac2dmToken, device_codename) self.gsfId = self.checkin(email, ac2dmToken)
if self.debug: if self.debug:
print("Google Services Framework Id: %s" % "{0:x}".format(self.gsfId)) print("Google Services Framework Id: %s" % "{0:x}".format(self.gsfId))
self.getAuthSubToken(email, encryptedPass) self.getAuthSubToken(email, encryptedPass)
@ -496,6 +496,9 @@ class GooglePlayAPI(object):
return self.delivery(packageName, versionCode, return self.delivery(packageName, versionCode,
offerType, dlToken, progress_bar=progress_bar) offerType, dlToken, progress_bar=progress_bar)
def changeDevice(self, device_codename):
self.deviceBuilder = config.DeviceBuilder(device_codename)
@staticmethod @staticmethod
def getDevicesCodenames(): def getDevicesCodenames():
return config.getDevicesCodenames() return config.getDevicesCodenames()