Skip to content

Instantly share code, notes, and snippets.

@rithvikvibhu
Last active April 12, 2024 15:32
Show Gist options
  • Save rithvikvibhu/1a0f4937af957ef6a78453e3be482c1f to your computer and use it in GitHub Desktop.
Save rithvikvibhu/1a0f4937af957ef6a78453e3be482c1f to your computer and use it in GitHub Desktop.
GHLocalApi Update

GHLocalApi Update

The Gist

Until recently, the Google Home app used to communicate with the device over port 8008 (HTTP) and did not require any authentication. Everything in the unofficial documentation worked as expected.

A few days (weeks) ago, Google pushed a new update to all GH devices and all endpoints (except /setup/eureka_info) started returning 403 (forbidden) errors. The app had switched over to port 8443 and HTTPS.

The Fix

Lots happened over at #39. Finally, the only changes required are:

  • Change port from 8008 to 8443
  • Change protocol from http to https
  • Add a new header (for all requests) cast-local-authorization-token

Note: Since this is https, the CA will likely not be trusted by your device. "Enable Insecure Requests" or "Allow Self Signed Certificates" when making requests. For example, pass the -k/--insecure flag with curl and verify=False with python's requests.

The Token

The token required for cast-local-authorization-token can be obtained by 2 methods. As of now, I'm not sure if this token expires or when it does or even how the app gets it in the first place.

/TODO: Add more info

Getting the token

2 ways: From app data directory on android or with Frida.

Both require root. First one recommended.

App Data Dir (Android)

This extracts the token from the app's data folder. The script finds tokens of all devices which might have this token. Only NodeJs is required, a browser friendly page coming soon.

Note: I ported the same code to a website so you don't have to download the script and NodeJs. The website finds all devices and tokens from the file and everything happens offline. Nothing from the file leaves the browser. https://rithvikvibhu.github.io/gh-web-proto-decode/

  • With a root file manager, pull this file: /data/data/com.google.android.apps.chromecast.app/files/home_graph*.proto
  • Run node decodeProtoFile.js <file> to extract tokens. (script attached)

With Frida (Android)

Frida injects and hooks onto running applications. The script logs all requests along with the needed header.

  • Install and set up Frida and ADB
  • Connect the phone to PC and copy Frida Server
  • Open the Google Home app on the phone
  • Use this script (thanks @TheKalin!)
  • Open GH settings in the app. The header with token will be printed.
const fs = require('fs');
const util = require('util');
const rawproto = require('rawproto');
const filename = process.argv[2] || 'home_graph.pb';
console.log(`[*] Reading proto binary... (${filename})`)
var buffer = fs.readFileSync(filename)
console.log(buffer)
console.log(`[*] Parsing file...`)
var data = rawproto.getData(buffer);
// detailedLog(data);
console.log('[*] Extracting tokens...\n')
data.forEach(val => {
if (val['2'] && Array.isArray(val['2'])) {
val['2'].forEach(val2 => {
if (val2['7'] && Array.isArray(val2['7'])) {
var device = null;
var token = null;
try {
var deviceObject = getObjByKey(val2['7'], '17')['17'][0];
device = (deviceObject ? (deviceObject['2'] || deviceObject['1']) + ', ' : '' ) + getObjByKey(val2['7'], '18')['18'][0]['2']
} catch (err) { console.log(err) }
try {
var tokenObject = getObjByKey(val2['7'], '28');
token = tokenObject ? tokenObject['28'] : null;
} catch (err) { console.log(err) }
if (device || token) {
console.log('Device:\t', device)
console.log('Token:\t', token)
console.log('-----')
}
}
})
}
})
console.log('\n[*] Done!\n')
function detailedLog(obj) {
console.log(util.inspect(obj, {showHidden: false, depth: null}))
}
function getObjByKey(arr, key) {
return arr.filter(v => v[key])[0]
}
@rithvikvibhu
Copy link
Author

@zapphyre I don't think Chromecasts have bluetooth modules, only Google Home devices do. But the rest of the docs should apply to Chromecasts as well.

@Mylmer
Copy link

Mylmer commented May 4, 2021

Hi, I am trying gh-web-proto-decode with my home_graphXXXX.proto but no devices found. Does gh-web-proto-decode working ?

Thanks for your reply.

@ptitsnake
Copy link

Hello,
I try to decode my proto file, I can upload it but the decode "Button" do nothing.
How can How can I recover the google Home token otherwise ?
THanks for your reply.

@JeedHome44
Copy link

Bonjour,
Votre page web ne marche plus?
J'ai utilisé VMOS sur un smartphone Android. J'ai activé root, j'ai téléchargé le fichier .proto
Mais quand je clique sur "Decode", rien ne se passe.
Le site a un problème?

@rithvikvibhu
Copy link
Author

The last update to this decoder was ~1.5 years ago. The proto file layout would've probably changed. I'll try to fix it this week.
In the mean time, you can simply open it in a text editor and look for a 108-char string that is close to your email address (ignore the garbage looking parts).

@JeedHome44
Copy link

Merci.
Donc si je comprends bien, je peux trouver le token de chaque appareil avec un éditeur de texte dans le fichier .proto?
C’est un token par appareil?
J’ai 14 Google Home chez moi.

pour avoir ce fichier proto, j’ai accédé à la racine. C’est bien comme ça qu’il faut faire?

@JeedHome44
Copy link

Pourrais je te demander plus de renseignements sur l'API GHLocal que tu as?
En fait, je suis l'administrateur du groupe Google Home FR sur Facebook.
J'ai aussi une chaîne Youtube: La Maison de Jeed Home.

Depuis une mise à jour il y a plus d'un an sur les Nest Hub, il y a une mise en veille automatique après 10 minutes qui affiche l'heure même si un cast web est en cours.
Avec Fuchsia OS, c'est au bout de 30 secondes.

Je veux désactiver ce mode veille automatique. C'est pour cela que je cherche les token de mes appareils en espérant pouvoir le désactiver comme ça vu que Google ne propose pas l'option sur son app smartphone.

Peux tu me dire si tu connais cette option et laquelle est-ce?

Tu vas aider beaucoup de gens si tu la connais.
J'ai demandé de nombreuses fois à Google mais ils restent fermés et ne partagent rien.

@JeedHome44
Copy link

dans mon fichier proto, je vois des lignes:
#google.com:api-project-XXXXXXXXXXXX[] XXXXXXXXXXXXXXXXXXXXXX*X
C'est ca?

@rithvikvibhu
Copy link
Author

The api-project-* is different. The actual token will be on its own and exactly 108 chars (only: letters, numbers, +, /).

Yes, it's 1 token per device, and only lasts about a day before it becomes invalid (and will need to be extracted again). So manually getting it every time is a pain, automated scripts help (like https://gist.github.com/rithvikvibhu/952f83ea656c6782fbd0f1645059055d). In the same link, @leikoilja has posted his cool python library that abstracts away all the complex logic: https://github.com/leikoilja/glocaltokens.

I don't have any Nest devices, so can't really be of much help here. If it's not possible to set it via the mobile app, then it may not be possible to do it via the API. Again, just guessing here.
Maybe you can open an issue on https://github.com/rithvikvibhu/GHLocalApi/issues/ in case someone stumbles upon it and knows how to change the sleep timeout.

@skisteep
Copy link

Been working on getting my Nest Thermostats with remote access for some time now, your work and Leikoilja's has been a great help, thx. When using Leikoilja's glocaltlokens package and I can capture my HomeGraph, but haven't been able to figure out how to decode the status values. Here is a sample of my HomeGraph Nest Device/Status

states {
  name: "ambientAirHumidity"
  value: "\035{\024.>"
}
states {
  name: "ambientAirTemperatureC"
  value: "\035\000\000\274A"
}
states {
  name: "ambientAirTemperature"
  value: "\035\000\000\224B"
}
states {
  name: "thermostatTemperatureSetpointC"
  value: "\035\000\000PA"
}
states {
  name: "thermostatTemperatureSetpoint"
  value: "\035\000\000\\B"
}

For Example I can change the "thermostatTemperatureSetpoint" via my iphone, then refresh the HomeGraph, and the value changes, so I know the HomeGraph is seeing my changes, BUT I haven't been able to decode the value, ie, value: "\035\000\000\B, any ideas on how to do this would be appreciated

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment