diff --git a/gpapi/config.py b/gpapi/config.py index a8cba62..4e2c653 100644 --- a/gpapi/config.py +++ b/gpapi/config.py @@ -19,20 +19,14 @@ GOOGLE_PUBKEY = "AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3iJIZdo # 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 +filepath = os.path.join(os.path.dirname(os.path.realpath(__file__)), + 'device.properties') + if VERSION == 2: config = ConfigParser.ConfigParser() else: config = configparser.ConfigParser() - -filepath = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'device.properties') 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(): @@ -50,92 +44,94 @@ def getDevicesReadableNames(): return output -def getUserAgent(): - return ("Android-Finsky/8.1.72.S-all [6] [PR] 165478484 (" - "api=3" - ",versionCode={versionCode}" - ",sdk={sdk}" - ",device={device}" - ",hardware={hardware}" - ",product={product}").format(versionCode=device['vending.version'], - sdk=device['build.version.sdk_int'], - device=device['build.device'], - hardware=device['build.hardware'], - product=device['build.product']) +class DeviceBuilder(object): + def __init__(self, device): + self.device = {} + for (key, value) in config.items(device): + self.device[key] = value -def getDeviceConfig(): - libList = device['sharedlibraries'].split(",") - featureList = device['features'].split(",") - localeList = device['locales'].split(",") - glList = device['gl.extensions'].split(",") - platforms = device['platforms'].split(",") + def getUserAgent(self): + return ("Android-Finsky/8.1.72.S-all [6] [PR] 165478484 (" + "api=3" + ",versionCode={versionCode}" + ",sdk={sdk}" + ",device={device}" + ",hardware={hardware}" + ",product={product}" + "").format(versionCode=self.device['vending.version'], + sdk=self.device['build.version.sdk_int'], + device=self.device['build.device'], + hardware=self.device['build.hardware'], + product=self.device['build.product']) - hasFiveWayNavigation = (device['hasfivewaynavigation'] == 'true') - hasHardKeyboard = (device['hashardkeyboard'] == 'true') - deviceConfig = googleplay_pb2.DeviceConfigurationProto() - deviceConfig.touchScreen = int(device['touchscreen']) - deviceConfig.keyboard = int(device['keyboard']) - deviceConfig.navigation = int(device['navigation']) - deviceConfig.screenLayout = int(device['screenlayout']) - deviceConfig.hasHardKeyboard = hasHardKeyboard - deviceConfig.hasFiveWayNavigation = hasFiveWayNavigation - deviceConfig.screenDensity = int(device['screen.density']) - deviceConfig.screenWidth = int(device['screen.width']) - deviceConfig.screenHeight = int(device['screen.height']) - deviceConfig.glEsVersion = int(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 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(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(",") -def getAndroidBuild(): - androidBuild = googleplay_pb2.AndroidBuildProto() - androidBuild.id = device['build.fingerprint'] - androidBuild.product = device['build.hardware'] - androidBuild.carrier = device['build.brand'] - androidBuild.radio = device['build.radio'] - androidBuild.bootloader = device['build.bootloader'] - androidBuild.device = device['build.device'] - androidBuild.sdkVersion = int(device['build.version.sdk_int']) - androidBuild.model = device['build.model'] - androidBuild.manufacturer = device['build.manufacturer'] - androidBuild.buildProduct = device['build.product'] - androidBuild.client = device['client'] - androidBuild.otaInstalled = False - androidBuild.timestamp = int(time.time()) - androidBuild.googleServices = int(device['gsf.version']) - return androidBuild + 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 + androidBuild.timestamp = int(time.time()) + androidBuild.googleServices = int(self.device['gsf.version']) + return androidBuild -def getAndroidCheckin(): - androidCheckin = googleplay_pb2.AndroidCheckinProto() - androidCheckin.build.CopyFrom(getAndroidBuild()) - androidCheckin.lastCheckinMsec = 0 - androidCheckin.cellOperator = device['celloperator'] - androidCheckin.simOperator = device['simoperator'] - androidCheckin.roaming = device['roaming'] - androidCheckin.userNumber = 0 - 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 + 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 diff --git a/gpapi/googleplay.py b/gpapi/googleplay.py index 72ec8d3..6ef2a67 100644 --- a/gpapi/googleplay.py +++ b/gpapi/googleplay.py @@ -46,11 +46,12 @@ class GooglePlayAPI(object): AUTHURL = BASE + "auth" ACCOUNT = "HOSTED_OR_GOOGLE" - def __init__(self, debug=False): + def __init__(self, debug=False, device_codename='bacon'): self.authSubToken = None self.gsfId = None self.lang = config.LANG self.debug = debug + self.deviceBuilder = config.DeviceBuilder(device_codename) def encrypt_password(self, login, passwd): """Encrypt the password using the google publickey, using @@ -87,7 +88,7 @@ class GooglePlayAPI(object): headers = { "Accept-Language": config.LANG.replace('_', '-'), "X-DFE-Encoded-Targets": config.DFE_TARGETS, - "User-Agent": config.getUserAgent() + "User-Agent": self.deviceBuilder.getUserAgent() } if self.gsfId is not None: headers["X-DFE-Device-Id"] = "{0:x}".format(self.gsfId) @@ -95,11 +96,11 @@ class GooglePlayAPI(object): headers["Authorization"] = "GoogleLogin auth=%s" % self.authSubToken return headers - def checkin(self, email, ac2dmToken, device_codename): + def checkin(self, email, ac2dmToken): headers = self.getDefaultHeaders() headers["Content-Type"] = "application/x-protobuffer" - request = config.getAndroidCheckinRequest(device_codename) + request = self.deviceBuilder.getAndroidCheckinRequest() stringRequest = request.SerializeToString() 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""" upload = googleplay_pb2.UploadDeviceConfigRequest() - upload.deviceConfiguration.CopyFrom(config.getDeviceConfig()) + upload.deviceConfiguration.CopyFrom(self.deviceBuilder.getDeviceConfig()) headers = self.getDefaultHeaders() 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" @@ -137,8 +138,7 @@ class GooglePlayAPI(object): headers=headers, verify=ssl_verify) googleplay_pb2.ResponseWrapper.FromString(res.content) - def login(self, email=None, password=None, gsfId=None, - authSubToken=None, device_codename='bacon'): + def login(self, email=None, password=None, gsfId=None, authSubToken=None): """Login to your Google Account. For first time login you should provide: * email @@ -185,7 +185,7 @@ class GooglePlayAPI(object): else: raise LoginError("Auth token not found.") - self.gsfId = self.checkin(email, ac2dmToken, device_codename) + self.gsfId = self.checkin(email, ac2dmToken) if self.debug: print("Google Services Framework Id: %s" % "{0:x}".format(self.gsfId)) self.getAuthSubToken(email, encryptedPass) @@ -496,6 +496,9 @@ class GooglePlayAPI(object): return self.delivery(packageName, versionCode, offerType, dlToken, progress_bar=progress_bar) + def changeDevice(self, device_codename): + self.deviceBuilder = config.DeviceBuilder(device_codename) + @staticmethod def getDevicesCodenames(): return config.getDevicesCodenames()