Changed login() behaviour

Previously, the ac2dm was meant to be saved in the application state, and later used for
subsequent logins, along with the gsfId. This is not correct, because the app needs it
only for the first login, and then remains unused in the application state.

The correct behaviour is to save the gsfId and the authSubToken, and provide only these two
values for subsequent logins

Signed-off-by: Domenico Iezzi <domenico.iezzi.201@gmail.com>
This commit is contained in:
Domenico Iezzi 2017-10-04 11:32:56 +02:00
parent 8b5eec3322
commit 2276f8db2c
3 changed files with 27 additions and 35 deletions

View File

@ -13,14 +13,14 @@ Check the test.py module for a simple example.
An important note about login function: An important note about login function:
``` ```
def login(self, email, password, ac2dmToken=None, gsfId=None) def login(self, email=None, password=None, gsfId=None, authSubToken=None)
``` ```
for first time logins, you should only provide email and password. for first time logins, you should only provide email and password.
The module will take care of retrieving an ac2dm token, registering The module will take care of initalizing the api,upload device information
"your device" to the google account you supplied, and retrieving to the google account you supplied, and retrieving
a Google Service Framework ID (which basically is the android ID of a device). a Google Service Framework ID (which, from now on, will be the android ID of a device).
For the next logins you **should** save the ac2dm master token and the gsfId (androidId), and provide them as parameters to the login function. If you login again with email and password only, this is the equivalent of deleting the google account from you device and re-initalize it every time. For the next logins you **should** save the gsfId and the authSubToken, and provide them as parameters to the login function. If you login again with email and password only, this is the equivalent of re-initalizing your android device with a google account.
# API reversing # API reversing

View File

@ -51,7 +51,6 @@ class GooglePlayAPI(object):
ACCOUNT = "HOSTED_OR_GOOGLE" ACCOUNT = "HOSTED_OR_GOOGLE"
authSubToken = None authSubToken = None
ac2dmToken = None
gsfId = None gsfId = None
def __init__(self, debug=False): def __init__(self, debug=False):
@ -94,13 +93,6 @@ class GooglePlayAPI(object):
if self.debug: if self.debug:
print("authSubToken: " + authSubToken) print("authSubToken: " + authSubToken)
def setAc2dmToken(self, ac2dmToken):
self.ac2dmToken = ac2dmToken
# put your auth token in config.py to avoid multiple login requests
if self.debug:
print("ac2dmToken: " + ac2dmToken)
def getDefaultHeaders(self): def getDefaultHeaders(self):
"""Return the default set of request headers, which """Return the default set of request headers, which
can later be updated, based on the request type""" can later be updated, based on the request type"""
@ -118,7 +110,7 @@ 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): def checkin(self, email, ac2dmToken):
headers = self.getDefaultHeaders() headers = self.getDefaultHeaders()
headers["Content-Type"] = "application/x-protobuffer" headers["Content-Type"] = "application/x-protobuffer"
@ -138,7 +130,7 @@ class GooglePlayAPI(object):
request2.id = response.androidId request2.id = response.androidId
request2.securityToken = response.securityToken request2.securityToken = response.securityToken
request2.accountCookie.append("[" + email + "]") request2.accountCookie.append("[" + email + "]")
request2.accountCookie.append(self.ac2dmToken) request2.accountCookie.append(ac2dmToken)
stringRequest = request2.SerializeToString() stringRequest = request2.SerializeToString()
res2 = requests.post(self.CHECKINURL, data=stringRequest, res2 = requests.post(self.CHECKINURL, data=stringRequest,
headers=headers, verify=ssl_verify) headers=headers, verify=ssl_verify)
@ -163,28 +155,19 @@ class GooglePlayAPI(object):
response = googleplay_pb2.ResponseWrapper.FromString(res.content) response = googleplay_pb2.ResponseWrapper.FromString(res.content)
def login(self, email, password, ac2dmToken=None, gsfId=None): def login(self, email=None, password=None, gsfId=None, authSubToken=None):
"""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
* password * password
For the following logins you need to provide all parameters (you For the following logins you need to provide:
should save gsfId and ac2dmToken somewhere""" * gsfId
encryptedPass = self.encrypt_password(email, password).decode('utf-8') * authSubToken"""
if (all( [each != None for each in [email, password, ac2dmToken, gsfId]] )): if email is not None and password is not None:
# this means that we already setup our account, we just need to get
# a token
self.setAc2dmToken(ac2dmToken)
self.gsfId = gsfId
self.getAuthSubToken(email, encryptedPass)
# check if token is valid with a simple search
self.search('firefox', 1, None)
else:
# First time setup, where we obtain an ac2dm token and # First time setup, where we obtain an ac2dm token and
# upload device information # upload device information
if (email is None or password is None):
raise Exception("You should provide both email and pass")
encryptedPass = self.encrypt_password(email, password).decode('utf-8')
# AC2DM token # AC2DM token
params = { params = {
"Email": email, "Email": email,
@ -209,19 +192,27 @@ class GooglePlayAPI(object):
k, v = d.split("=")[0:2] k, v = d.split("=")[0:2]
params[k.strip().lower()] = v.strip() params[k.strip().lower()] = v.strip()
if "auth" in params: if "auth" in params:
self.setAc2dmToken(params["auth"]) ac2dmToken = params["auth"]
elif "error" in params: elif "error" in params:
raise LoginError("server says: " + params["error"]) raise LoginError("server says: " + params["error"])
else: else:
raise LoginError("Auth token not found.") raise LoginError("Auth token not found.")
self.gsfId = self.checkin(email) 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)
if self.debug: if self.debug:
print("Uploading device configuration") print("Uploading device configuration")
self.uploadDeviceConfig() self.uploadDeviceConfig()
elif gsfId is not None and authSubToken is not None:
# no need to initialize API
self.gsfId = gsfId
self.setAuthSubToken(authSubToken)
# check if token is valid with a simple search
self.search('firefox', 1, None)
else:
raise LoginError('Either (email,pass) or (gsfId, authSubToken) is needed')
def getAuthSubToken(self, email, passwd): def getAuthSubToken(self, email, passwd):
params = { params = {

View File

@ -6,16 +6,17 @@ EMAIL = "maracaiboez"
PASSWD = "fjgozwjmkwyvvutt" PASSWD = "fjgozwjmkwyvvutt"
testApps = ['com.cpuid.cpu_z'] testApps = ['com.cpuid.cpu_z']
server = GooglePlayAPI(True) server = GooglePlayAPI(debug=True)
try: try:
print('\nLogging in with email and password\n') print('\nLogging in with email and password\n')
server.login(EMAIL, PASSWD, None, None) server.login(EMAIL, PASSWD, None, None)
ac2dmToken = server.ac2dmToken
gsfId = server.gsfId gsfId = server.gsfId
authSubToken = server.authSubToken
print('\nNow trying secondary login with ac2dm token and gsfId saved\n') print('\nNow trying secondary login with ac2dm token and gsfId saved\n')
server.login(EMAIL, PASSWD, ac2dmToken, gsfId) server = GooglePlayAPI(debug=True)
server.login(None, None, gsfId, authSubToken)
apps = server.search('telegram', 1, None) apps = server.search('telegram', 1, None)
print('\nFound those apps:\n') print('\nFound those apps:\n')