How it works - Norman0406/Slimgress GitHub Wiki

Authentication

Ingress uses the Google App Engine and all functionality provided by it. I.e., the user has to authenticate against the server using a Google OAuth2 token. To obtain the token, the user has to allow the application to use profile data.

With android, the way to go is the AccountManager and selecting the google account installed on the device by using AccountManager.getAccountsByType("com.google"). If multiple accounts are installed, the user can select which one to use. The AccountManager is then used to obtain an authentication token using getAuthToken and token type "ah". This authenticates for access to a Google App Engine server.

Once the authentication token os obtained, the user has to authenticate against the server. This is done with a simple HttpGet on

https://m-dot-betaspike.appspot.com/_ah/login?continue=http://localhost/&auth=

with the last parameter being the OAuth2 token. For any reason, redirects should be enabled for this request but intercepted using the response status code 302. If the response contains status code 401, the token is most likely expired and has to be renewed using AccountManager.invalidateAuthToken(). If authentication was successful, a secure cookie (SACSID) is retrieved and has to be saved for later access to the API.

Handshake

The handshake is used to exchange some general data between client and server. The client tells the server which software and android version it is using and the server in return gives some information about the user and the game state. It also decides whether or not the client is allowed to participate in the game, based on the software version.

The handshake is again done using HttpGet:

https://m-dot-betaspike.appspot.com/handshake?json=

with handshake parameters

{nemesisSoftwareVersion="2013-07-12T15:48:09Z d6f04b1fab4f opt",deviceSoftwareVersion="4.2.0"}

Nemesis was the code name for Ingress, and the corresponding software version can be found in the ingress app under OPS->DEVICE->Build. It seems to be important to add "opt" here.

At this point it is important to note that all the server communication is done using JSON (java script object notation). This is a simple text based data interchange format based on JavaScript. Indeed every JSON file poses a valid JavaScript file. However, it is just an alternative to other data interchange formats like XML, though using less memory and bandwidth. JSON can also be processed in Java using an efficient and simple JSON parser (org.json.*).

The returned handshake data contains information about the game state and the player, i.e. nickname, ap, xm energy, and whether the player is allowed to play. Most importantly, the handshake contains yet another token called "xsrfToken".

Requesting

Now it's time to send requests to the api. For requesting api calls, HttpPost is used on

https://m-dot-betaspike.appspot.com/rpc/

following a request string identifying the function to call, such as

playerUndecorated/getInventory

The header type for the post has to be set to

  • "Content-Type": "application/json;charset=UTF-8"
  • "Accept-Encoding": "gzip"
  • "User-Agent": "Nemesis (gzip)"
  • "X-XsrfToken": the "xsrfToken" from the handshake data
  • "Host": "m-dot-betaspike.appspot.com"
  • "Connection": "Keep-Alive"
  • "Cookie": "SACSID=" + the cookie returned with authentication

The encoding does not necessarily be set to "gzip", but it saves a lot of bandwidth and is easy to decompress. Last, almost every api call needs additional parameters, which are set in JSON and passed as an entity to the post. The precise parameters vary between the calls, but most of them use at least some of the following:

  • "playerLocation": the player location in E6 format, e.g. "50345750,07591669"
  • "location": same as "playerLocation"
  • "knobSyncTimestamp": the current UNIX timestamp
  • "energyGlobGuids": a list of xm guids the scanner wants to collect

It is important to set the content type for the entity to "application/json" and format the string in UTF-8.