RoeiOfri / homebridge-palgate-opener

PalGates homebridge plugin
MIT License
27 stars 8 forks source link

Token extraction tool doesn't work anymore #17

Open zcahana opened 2 years ago

zcahana commented 2 years ago

Recently the authentication flow used by the PalGate app has been changed, and the current (old) auth endpoint used results with the following error returned from the server:

{'error': 'resource not found, check api path'}

I've tried to reverse engineer the new auth flow by looking at the app logs, but couldn't extract a usable token. Here's how it looks like in the app's logs (some token/IDs removed):

01-24 18:15:55.186 23929 24033 I okhttp.OkHttpClient: --> POST https://api1.pal-es.com/v1/bt/un/k11
01-24 18:15:55.186 23929 24033 I okhttp.OkHttpClient: Content-Type: application/json; charset=UTF-8
01-24 18:15:55.186 23929 24033 I okhttp.OkHttpClient: Content-Length: 89
01-24 18:15:55.186 23929 24033 I okhttp.OkHttpClient: {"s":"<some serial>","v":1,"k":"<some key1>"}
01-24 18:15:55.186 23929 24033 I okhttp.OkHttpClient: --> END POST (89-byte body)
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: <-- 200 https://api1.pal-es.com/v1/bt/un/k11 (196ms)
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: date: Mon, 24 Jan 2022 16:15:56 GMT
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: content-type: application/json; charset=utf-8
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: content-length: 65
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: access-control-allow-origin: *
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: access-control-allow-methods: GET,PUT,POST,DELETE,OPTIONS
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, X-Access-Token, x-bt-app-token, x-bt-user-token, X-Key, x-device-token, x-dev
ice-id
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: access-control-max-age: 600
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: strict-transport-security: max-age=15724800; includeSubDomains
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: {"err":null,"status":"ok","k":"<some key2>"}
01-24 18:15:55.383 23929 24033 I okhttp.OkHttpClient: <-- END HTTP (65-byte body)
01-24 18:15:55.387 23929 24034 I okhttp.OkHttpClient: --> POST https://api1.pal-es.com/v1/bt/un/verify/start/+<phonenumber>?countryCode=il&os=android
01-24 18:15:55.387 23929 24034 I okhttp.OkHttpClient: Content-Type: application/json; charset=UTF-8
01-24 18:15:55.387 23929 24034 I okhttp.OkHttpClient: Content-Length: 102
01-24 18:15:55.387 23929 24034 I okhttp.OkHttpClient: {"s":"<some serial>","v":1,"k":"<some key3>","type":"sms"}
01-24 18:15:55.387 23929 24034 I okhttp.OkHttpClient: --> END POST (102-byte body)
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: <-- 200 https://api1.pal-es.com/v1/bt/un/verify/start/+<phonenumber>?countryCode=il&os=android (1018ms)
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: date: Mon, 24 Jan 2022 16:15:57 GMT
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: content-type: application/json; charset=utf-8
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: content-length: 122
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: access-control-allow-origin: *
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: access-control-allow-methods: GET,PUT,POST,DELETE,OPTIONS
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, X-Access-Token, x-bt-app-token, x-bt-user-token, X-Key, x-device-token, x-dev
ice-id
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: access-control-max-age: 600
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: strict-transport-security: max-age=15724800; includeSubDomains
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: {"err":null,"msg":"Message sent to <phonenumber>","status":"ok","pn":"<phonenumber>","k":"<some key4>"}
01-24 18:15:56.406 23929 24034 I okhttp.OkHttpClient: <-- END HTTP (122-byte body)
01-24 18:16:00.699 23929 24079 I okhttp.OkHttpClient: --> POST https://api1.pal-es.com/v1/bt/un/verify/code/<phonenumber>?countryCode=il
01-24 18:16:00.699 23929 24079 I okhttp.OkHttpClient: Content-Type: application/json; charset=UTF-8
01-24 18:16:00.699 23929 24079 I okhttp.OkHttpClient: Content-Length: 104
01-24 18:16:00.699 23929 24079 I okhttp.OkHttpClient: {"code":"<code sent by sms>","s":"some serial","v":1,"k":"<some key5>"}
01-24 18:16:00.699 23929 24079 I okhttp.OkHttpClient: --> END POST (104-byte body)
01-24 18:16:00.718 23929 23929 W IInputConnectionWrapper: getExtractedText on inactive InputConnection
01-24 18:16:00.719 23929 23929 W IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: <-- 200 https://api1.pal-es.com/v1/bt/un/verify/code/<phonenumber>?countryCode=il (149ms)
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: date: Mon, 24 Jan 2022 16:16:01 GMT
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: content-type: application/json; charset=utf-8
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: content-length: 222
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: access-control-allow-origin: *
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: access-control-allow-methods: GET,PUT,POST,DELETE,OPTIONS
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, X-Access-Token, x-bt-app-token, x-bt-user-token, X-Key, x-device-token, x-dev
ice-id
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: access-control-max-age: 600
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: strict-transport-security: max-age=15724800; includeSubDomains
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: {"err":null,"msg":"user verified, existing user","status":"ok","user":{"id":"<phonenumber>","token":"<a token>","address":"","firstna
me":"<firstname>","lastname":"<lastname>","image":false,"userexist":true}}
01-24 18:16:00.849 23929 24079 I okhttp.OkHttpClient: <-- END HTTP (222-byte body)

As for the last token received in the last response, I've tried using it as the value of the x-bt-token / x-bt-user-token headers in http requests, but this results with {"errId":7101,"status":"401","msg":"Invalid Token or Key"}.

I'm wondering if anyone was able to figure out how to use the new auth flow?

zcahana commented 2 years ago

So, I examined the HTTP requests sent by the app (using the interception method suggested here).

It appears that the app now rotates the auth token for (almost) every outgoing request. Occasionally, the same token is reused across several adjacent (in time) requests. Attempting to repeat (with curl) a request with the exact same token previously used for it, fails with 401, so these tokens must have some short-lived expiry mechanism.

The token itself is a 46-digits hexadecimal string such as 0100E9405D782800B6E989591EF07612EF823626290892, whereas the first 12 digits are constant across all tokens. No clue about the rest of the 34 digits. But note that the "k" parameter exchanged (several times) in the 3 auth flow requests described above, as well as the final "token" parameter, are all 34 hexa digits too (each, a different one).

Anyway, I'm completely clueless about how these tokens are generated, but hopefully it can ring someone's bells.

BuSHari commented 2 years ago

So, I examined the HTTP requests sent by the app (using the interception method suggested here).

It appears that the app now rotates the auth token for (almost) every outgoing request. Occasionally, the same token is reused across several adjacent (in time) requests. Attempting to repeat (with curl) a request with the exact same token previously used for it, fails with 401, so these tokens must have some short-lived expiry mechanism.

The token itself is a 46-digits hexadecimal string such as 0100E9405D782800B6E989591EF07612EF823626290892, whereas the first 12 digits are constant across all tokens. No clue about the rest of the 34 digits. But note that the "k" parameter exchanged (several times) in the 3 auth flow requests described above, as well as the final "token" parameter, are all 34 hexa digits too (each, a different one).

Anyway, I'm completely clueless about how these tokens are generated, but hopefully it can ring someone's bells.

I had this token for an example 0100E26EE9D9BC31FA8420ECC71C0BB3A540A3F07B8E0C and in all my requests the first 14 chars are constant across all my tokens (and not 12 like you). i think the token is built with timestamp in the hex that is being verifeid againt one of the requests.

i'm also clueless regarding how these tokens are generated :(

zcahana commented 2 years ago

Any chance someone from Pal will step in to the rescue? 🙏🏼

BuSHari commented 2 years ago

Any chance someone from Pal will step in to the rescue? 🙏🏼

I think they change it because of this plugin (and others)

bmyonatan commented 2 years ago

I think indeed the token is timestamp based. I don't have any experience in reverse engineering android apps, but a simple decomplie and search for "token" showed the following function in the app's code:

  public static String getToken(Context paramContext, Integer paramInteger) {
    long l3;
    long l1 = System.currentTimeMillis() / 1000L;
    long l2 = Preferences.from(paramContext).getLong("timeStampLong").longValue();
    String str1 = Preferences.from(paramContext).getString("userId");
    String str2 = Preferences.from(paramContext).getString("sessionToken");
    a.a a = a.a;
    if (!str1.equals("")) {
      l3 = Long.parseLong(str1);
    } else {
      l3 = 0L;
    } 
    return IntToHexString(FaceDetectNative.getInstance().getFacialLandmarks(hexStringToByteArray(str2), l2 + l1, l3, paramInteger.intValue()));
  }

  public static Integer getTokenType(Context paramContext) {
    return Preferences.from(paramContext).getInt("tokenType");
  }

  public static String getUserSessionToken(Context paramContext, Integer paramInteger) {
    Integer integer = paramInteger;
    if (paramInteger.intValue() == -1)
      integer = getTokenType(paramContext); 
    return getToken(paramContext, integer);
  }

Also, I examined the HTTP flow as well: first the app issues a GET request to https://api1.pal-es.com/v1/bt/un/ts and receives a timestamp in the response.
Then a request to /v1/bt/user/checkupdate?v=4 containing an x-bt-token header, receiving a "no updates exist" msg and deviceHash built from 8 characters.
Then there is a request to https://api1.pal-es.com/v1/bt/user/check-token, with a x-bt-token, and it receives a "token valid" msg and a ts value finally there is a request to https://api1.pal-es.com/v1/bt/device/<device_key>/open-gate?outputNum=1 including a x-bt-token (all tokens in this process are different) image

BuSHari commented 2 years ago

I think indeed the token is timestamp based. I don't have any experience in reverse engineering android apps, but a simple decomplie and search for "token" showed the following function in the app's code:

  public static String getToken(Context paramContext, Integer paramInteger) {
    long l3;
    long l1 = System.currentTimeMillis() / 1000L;
    long l2 = Preferences.from(paramContext).getLong("timeStampLong").longValue();
    String str1 = Preferences.from(paramContext).getString("userId");
    String str2 = Preferences.from(paramContext).getString("sessionToken");
    a.a a = a.a;
    if (!str1.equals("")) {
      l3 = Long.parseLong(str1);
    } else {
      l3 = 0L;
    } 
    return IntToHexString(FaceDetectNative.getInstance().getFacialLandmarks(hexStringToByteArray(str2), l2 + l1, l3, paramInteger.intValue()));
  }

  public static Integer getTokenType(Context paramContext) {
    return Preferences.from(paramContext).getInt("tokenType");
  }

  public static String getUserSessionToken(Context paramContext, Integer paramInteger) {
    Integer integer = paramInteger;
    if (paramInteger.intValue() == -1)
      integer = getTokenType(paramContext); 
    return getToken(paramContext, integer);
  }

Also, I examined the HTTP flow as well: first the app issues a GET request to https://api1.pal-es.com/v1/bt/un/ts and receives a timestamp in the response. Then a request to /v1/bt/user/checkupdate?v=4 containing an x-bt-token header, receiving a "no updates exist" msg and deviceHash built from 8 characters. Then there is a request to https://api1.pal-es.com/v1/bt/user/check-token, with a x-bt-token, and it receives a "token valid" msg and a ts value finally there is a request to https://api1.pal-es.com/v1/bt/device/<device_key>/open-gate?outputNum=1 including a x-bt-token (all tokens in this process are different) image

Great! Can you please send me the full decompiled code? I knew this token includes a timestamp, but didn’t knew what else they added to convert it to hex, from that code I can create a flow to generate the token.

bmyonatan commented 2 years ago

Sure palgate decompiled

zcahana commented 2 years ago

@bmyonatan awesome, that's very helpful! I too glimpsed into the decompiled code, and it seems that most is there in order to reconstruct and automate the authentication flow (although they definitely didn't make this an easy task 😄)

A missing piece is the implementation of FaceDetectNative.getFacialLandmarks(). This method is implemented via a native library (see System.loadLibrary("native-lib") in com/bluegate/app/utils/FaceDetectNative.java). Did you happen to see any hint of native-lib or getFacialLandmarks() in the app files you decompiled? The generic name suggests that this is something bundled with the app...

zcahana commented 2 years ago

Found the native library in the app apk's: libnative-lib.zip And here's its aarch64 disassembly: https://onlinedisassembler.com/odaweb/NJcFdjfX (see Java_com_bluegate_app_utils_FaceDetectNative_getFacialLandmarks).

Anyone wants to take a shot at deciphering that? I thought so 😄

One option is to try to understand what's the source of this object file. Another option is to try to load and run that code via some arm emulator. I don't know if that's feasible for this homebridge plugin here, but might be feasible for my use (palgate-cli).

Anyway, quite a lot of headache for one little token 😆

zcahana commented 2 years ago

https://stackoverflow.com/questions/71255467/what-is-android-facedetectnative-getfaciallandmarks Looks like we're not alone...

adi6409 commented 2 years ago

so, is there a fix for this? perhaps the plugin could use the same timestamp based method to cycle the token.

zcahana commented 2 years ago

perhaps the plugin could use the same timestamp based method to cycle the token.

There's no easy way to do this because some of the token generation code uses a function from a native library loaded at runtime. At first I thought we can load it too using some arm64 emulator (e.g. qemu-user-aarch64) but the library also seem to have dependencies on android OS itself so it's not sufficient to emulate the architecture. Hopefully someone with some Android emulation experience can take a shot at this.

RoeiOfri commented 2 years ago

@nitaybz maybe you can assist?

adi6409 commented 1 year ago

Following up- I think a good step might be creating a proof-of-concept android app/code that successfully opens a gate with the new token system. after that is done, we could move forward with android emulation, which in theory should be possible because the pi is arm64.

tzachi-dar commented 1 year ago

Here is a simple workaround for the problem. Take an old android phone. Make sure it is able to open the gate using the palgate application. Install Macdroid (free app) on the phone. Create a macro that opens the gate with the following parameters:

trigger: network capture define an identifier

Actions Open palgate Wait 1 second User interaction. Presses x,y (209, 500)

You will get a url that once called, opens the gate. This requires an old phone, but don't tell me you don't have one.

tzachi-dar commented 1 year ago

Here is the macro that was saved. remove the .txt extantion. Macro might be a little different, as it depends on screen size and so on. Yru.macro.txt

EladBezalel commented 1 year ago

I also managed to bypass the palgate app, unlike @tzachi-dar, instead of having a physical phone with macro, I created an internal webserver that uses google-asistant-sdk (there are probably better implementations to it), when you get the endpoint, i make a call to google assistant through the sdk to open gate. then i connected it to Telegram/Whatsapp and managed to give access to whoever is needed :)

adi6409 commented 1 year ago

Sounds great! do you mind sharing the source code?

EladBezalel commented 1 year ago

Actually, it's pretty simple using https://github.com/googlesamples/assistant-sdk-nodejs Follow the setup steps and then wrap it with express

const express = require("express");
const url = require("url");
const GoogleAssistant = require("./googleassistant");
const deviceCredentials = require("./devicecredentials.json");

const app = express();
const port = process.env.PORT || 1234;

const CREDENTIALS = {
  client_id: deviceCredentials.client_id,
  client_secret: deviceCredentials.client_secret,
  refresh_token: deviceCredentials.refresh_token,
  type: "authorized_user",
};

const assistant = new GoogleAssistant(CREDENTIALS);

app.get("/", async (req, res) => {
  const query = url.parse(req.url, true).query;
  const response = await assistant.assist(query.text);

  res.send(response.text);
});

app.listen(port, () => {
  console.log(`Server started on port ${port}`);
});

googleassistant.js file is from the lib mentioned above

So then just query localhost:1234/?text="open gate" (notice that for some questions you'd get an empty response, you can follow the issue here https://github.com/googlesamples/assistant-sdk-nodejs/issues/13, i recommend asking obama's height - always responses with text :) )

FYI this approach uses my PERSONAL google assistant


For the whatsapp bot i used https://github.com/pedroslopez/whatsapp-web.js/

import { Client, LocalAuth } from "whatsapp-web.js";
import * as qrcode from "qrcode-terminal";
import { actions } from "./actions"; // this is an object with all actions

/**
* actions = {
*   gate: () => // request to the google api service
* }
*/

const client = new Client({
  authStrategy: new LocalAuth({
    dataPath: "./data",
  }),
  puppeteer: {
    args: [ // args to run in docker
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-dev-shm-usage",
    ],
  },
  userAgent:
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
});

client.on("qr", (qr) => {
  qrcode.generate(qr, { small: true });
});

client.on("ready", () => {
  console.log("Client is ready!");
});

client.on("message", async (message) => {
  if (!message.body.startsWith("!")) {
    return;
  }

  const commandName = message.body.replace("!", "").toLowerCase();

  console.log(`Received: '${message.body}' from ${message.from}`);

  if (!actions[commandName]) {
    console.log("no action found");
    return;
  }

  try {
    console.log(`running action ${commandName}`);
    await actions[commandName](message);
  } catch (e) {
    console.log(e);
    message.reply("error");
  } finally {
    console.log("done");
  }
});

try {
  console.log("starting...");
  client.initialize().catch((_) => {
    console.log("error", _);
  });
} catch (e) {
  console.log(e);
}
RoeiOfri commented 1 year ago

@EladBezalel , I understand that you actually bypassed the PalGate app, but I didn't understand what have you done with the token, are you sending the request directly from your local webserver? (so it seems) But since it's a rolling token and the token is only alive for a single use and only for 1 min expiration I didn't understand where's the token reference in the code you publish above, can you elaborate?

I must say, I found some sort of bypass but that stopped working today so again it's a dead-end for me.

bengry commented 1 year ago

@EladBezalel , I understand that you actually bypassed the PalGate app, but I didn't understand what have you done with the token, are you sending the request directly from your local webserver? (so it seems) But since it's a rolling token and the token is only alive for a single use and only for 1 min expiration I didn't understand where's the token reference in the code you publish above, can you elaborate?

The workaround he's using is by leveraging the Palgate <-> Google Assistant integration (which is a Palgate feature). The webserver is calling Google, which in turn calls the Palgate servers. The webserver is just acting as a Google Assistant client and that's it.

As a personal note, while this works, and is a pretty generic solution to anything that has a Google Assistant integration but not a HA one, it has an additional (noticeable) latency - since you're going through Google's API which also needs to parse the command, forward it to whatever service it needs to go to and only then Palgate starts acting.

RoeiOfri commented 1 year ago

I think that understanding this part is our main goal (from @BuSHari 's comment):

 long l3;
    long l1 = System.currentTimeMillis() / 1000L;
    long l2 = Preferences.from(paramContext).getLong("timeStampLong").longValue();
    String str1 = Preferences.from(paramContext).getString("userId");
    String str2 = Preferences.from(paramContext).getString("sessionToken");
RoeiOfri commented 1 year ago

@bengry Oh I see, well it's a nice W/A but doesn't fit our needs, our main goal is to understand how the token generation works :/

Klakk18 commented 1 year ago

Was it possible to find out the process of token formation?

the-mentor commented 1 year ago

I found the AuthToken and refresh token via a rooted Android device in the following path cat /data/data/com.bluegate.app/files/PersistedInstallation.******.json

here is the Is the content with redacted information

{
  "Fid": "redacted-fid",
  "Status": 3,
  "AuthToken": "redacted-token",
  "RefreshToken": "redacted-refresh-token",
  "TokenCreationEpochInSecs": 1684852460,
  "ExpiresInSecs": 604800
}

not sure if it can help us or not.

codedninja commented 1 year ago

Just moved into a new place with a Palgate system. I was looking for ways to create a garage door style opener for the car and came across this.

Seems like no one has been able to reverse engineer the nativelib yet. For more context there is an x86 and x64 versions of the shared object.

I am working on reverse engineering the binary. I have their AES encryption/decryption function with their AES Key and IV working already. Working on creating their hash/check function next.

I have only spent one sleepless night on reversing it so far so give me a little more time and I will give more updates.

Edit: The x86 version of the library is easier to re-implement from my first glance.

armanism commented 1 year ago

I thin the easiest way is to write a program to work with the standard library. And run it on the raspberry pi board.

codedninja commented 1 year ago

It import shared libraries from the Android system, so it's not really the easiest. Personally I think the easiest way would be wrapping the library for Android x86 with an HTTP endpoint.

I am currently have the APK running on Android x86 perfectly fine and debugging it remotely with GDB to double check my work.

RoeiOfri commented 1 year ago

@codedninja Amazing work, thank you for your assistance. Please do keep up posted. 🍻

RoeiOfri commented 1 year ago

I came across I came across this if it will assist someone.

Knilo commented 9 months ago

I have had another look at the native library. Most of it is a set of functions to perform encryption and decryption. The hard part here will be figuring out the key which seems to be partly from the l3 (userToken converted from Strong to Long) input to the getFacialLandmarks and some predetermined array of bytes (T_C_KEY), where:

T_C_KEY[6] = 0x34 T_C_KEY[7] = 0xf4 T_C_KEY[8] = 0x47 T_C_KEY[9] = 0xc3 T_C_KEY[10] = 0x8d T_C_KEY[11] = 0xe1

There is another function aes_enc_dec does most of the heavy cryptographic lifting. Given this, it may be possible to reverse engineer given some security expertise, but not sure I can get much further.

codedninja commented 9 months ago

Tomorrow I am gonna push the code I have done reimplementing everything. I have completed some parts. Though I was having issues reimplementing something that uses the timestamp from their servers. I have already extracted their key and will be inside of the code I push.

RoeiOfri commented 9 months ago

@codedninja This is amazing! Thank you!

alex-sapronov commented 9 months ago

Hi, @codedninja. Where can we see your changes?

rubeecube commented 9 months ago

Hi @codedninja, if it's a matter of putting parts of code together, or debug stuff I can help

roydbt commented 8 months ago

Any there any updates? It's been more than a month since @codedninja 's last comment

OriAshkenazi commented 8 months ago

I'm waiting for news too. That's the last part of the "smart home puzzle" for me :)

andybenichou commented 6 months ago

Hi, have we got any updates?

andybenichou commented 6 months ago

Do you have a way to get the token without the extractor maybe by sniffing the requests from network when using the app on mac?

hllhll commented 2 months ago

Just putting my post here so some ppl might bug me in the near future to check this out... I would probably try to look into this also try to implement in python (I'm a HomeAssistant user, not Homebridge though), or just wrap it in a java class with changes/mocks and throw it into py4j

appkins commented 1 month ago

This looks like it may be firebase authentication. I recommend installing certs on a mobile device and running the app behind something like Postman proxy to decrypt all the packets. It may be possible to use the firebase npm package to spoof the initial token creation from the values you find.

Assuming it is firebase, it explains why the decompiled cryptology is hard to work through.

Knilo commented 1 week ago

I am happy to try and implement it if no one has yet

RoeiOfri commented 1 week ago

This won't work, see the readme of that repo, it redirects to my repo for sniffing the token hence it will not work.

armanism commented 1 week ago

I thin the easiest way is to write a program to work with the standard library. And run it on the raspberry pi board.

It's not working now...

3052 commented 5 days ago

note that I am now offering a 900 USD bounty if anyone can solve this. my contact info on my profile page