ph4r05/ph4-walkingpad

question

Opened this issue · 22 comments

Hello,
First of all thank you very much for sharing this, it seems to be working with my R1 PRO walkingpad.
Have a few question if you have the time to address them.

  1. How do you grab the JWT token from the app?
  2. I've been looking for docs for the walkingpad API, how did you manage to find it? Reversed engineered it? :)
  3. How can i donate ? 👍

Thanks again!
Vlad

@WladyX thanks for reaching out! I am glad you found this useful.

I've updated the README as I got similar question by email lately.

  1. JWT - from the adb logcat, Android app logs it directly :)
  2. adb logcat, logging is very generous.
  3. I've added donation options to the README (bottom), Thanks!

Unfortunately, I did not have time to figure out how the communication with the server is done with respect to authentication. But I think after a while you could easily find the login request so you can query JWT on your own, without needing the original app.

JWT is valid maybe for a month or so.

@ph4r05 Hello, you helped me with bluetooth packets very well, for this moment I found almost everything request types and responses. This is what I've done for now :)

doc.mp4

@rewhex did you also find the API & JWT? I see you also have a R1 PRO.
I haven't been able to find them in logs.
The JWT i suspect is this one:

05-03 19:46:53.529 27926 30705 I flutter : lyt----- k9 firmware map {service: user.firmware, xjid: 1046575, model: R1_bt, token: REDACTED_TOKEN, app_ver: 3.5.30, firmware_ver: 5, wifi_ver: null}

But not a clue about the API.

@rewhex did you also find the API & JWT? I see you also have a R1 PRO.
I haven't been able to find them in logs.
The JWT i suspect is this one:

05-03 19:46:53.529 27926 30705 I flutter : lyt----- k9 firmware map {service: user.firmware, xjid: 1046575, model: R1_bt, token: REDACTED_TOKEN, app_ver: 3.5.30, firmware_ver: 5, wifi_ver: null}

But not a clue about the API.

No, because I don't want to use all the API from official app, the only reason to use it is firmware updates, but I think they will release updates not very often, so I will not implement this.

If you really need this, you can patch official APK file network config file to support user proxy certificates, and sniff for network traffic on your phone through mitm proxy, read more about it here: mitm.it

@WladyX I've just checked the logs. In the app I am using the JWT token is easy to find, just look for base64-url encoded blob, usually in the cookies. Maybe try looking around logs contentType: application/json

05-10 10:45:36.128 29458 21314 I flutter : lyt-------请求url https://eu.app.walkingpad.com/user/api/v2/record
05-10 10:45:36.128 29458 21314 I flutter : user=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VyIjp7ImlkIjoxMjM0NTYsImVtYWlsIjoicGg0cjA1QGdtYWlsLmNvbSIsImRpc3RhbmNlX3VuaXQiOiJrbSIsImhlaWdodF91bml0IjoibSIsIndlaWdodF91bml0Ijoia2ciLCJiaXJ0aCI6Im5vdC10ZWxsaW5nIiwiZ2VuZGVyIjp0cnVlLCJoZWlnaHQiOjEuOCwid2VpZ2h0Ijo4MCwiZ3VpZGVfaW5mbyI6dHJ1ZX0sImV4cCI6MTYxODA0OTU3NCwiaXNzIjoiZ2VuZXJhdGUgdG9rZW4ifQ.NXqkC7EI44sQm4_xLYchuHhdwXRwPYRziRI_a6Oop-k; Path=/; Expires=Sat, 10 Apr 2021 10:12:54 GMT; HttpOnly
05-10 10:45:36.128 29458 21314 I flutter : *** Request ***
05-10 10:45:36.128 29458 21314 I flutter : uri: https://eu.app.walkingpad.com/user/api/v2/record
05-10 10:45:36.128 29458 21314 I flutter : method: POST
05-10 10:45:36.129 29458 21314 I flutter : contentType: application/json; charset=utf-8
05-10 10:45:36.129 29458 21314 I flutter : responseType: ResponseType.plain
05-10 10:45:36.129 29458 21314 I flutter : followRedirects: true
05-10 10:45:36.129 29458 21314 I flutter : connectTimeout: 10000
05-10 10:45:36.129 29458 21314 I flutter : receiveTimeout: 10000
05-10 10:45:36.129 29458 21314 I flutter : extra: {}
05-10 10:45:36.129 29458 21314 I flutter : header:
05-10 10:45:36.129 29458 21314 I flutter :   cookie:[user=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VyIjp7ImlkIjoxMjM0NTYsImVtYWlsIjoicGg0cjA1QGdtYWlsLmNvbSIsImRpc3RhbmNlX3VuaXQiOiJrbSIsImhlaWdodF91bml0IjoibSIsIndlaWdodF91bml0Ijoia2ciLCJiaXJ0aCI6Im5vdC10ZWxsaW5nIiwiZ2VuZGVyIjp0cnVlLCJoZWlnaHQiOjEuOCwid2VpZ2h0Ijo4MCwiZ3VpZGVfaW5mbyI6dHJ1ZX0sImV4cCI6MTYxODA0OTU3NCwiaXNzIjoiZ2VuZXJhdGUgdG9rZW4ifQ.NXqkC7EI44sQm4_xLYchuHhdwXRwPYRziRI_a6Oop-k; Path=/; Expires=Sat, 10 Apr 2021 10:12:54 GMT; HttpOnly]
05-10 10:45:36.129 29458 21314 I flutter :

I usually do

adb logcat | tee android.log

When I see an interesting log I get back to the line in the android.log.

@WladyX I've just checked the logs. In the app I am using the JWT token is easy to find, just look for base64-url encoded blob, usually in the cookies. Maybe try looking around logs contentType: application/json

05-10 10:45:36.128 29458 21314 I flutter : lyt-------请求url https://eu.app.walkingpad.com/user/api/v2/record
05-10 10:45:36.128 29458 21314 I flutter : **; Path=/; Expires=Sat, 10 Apr 2021 10:12:54 GMT; HttpOnly
05-10 10:45:36.128 29458 21314 I flutter : *** Request ***
05-10 10:45:36.128 29458 21314 I flutter : uri: https://eu.app.walkingpad.com/user/api/v2/record
05-10 10:45:36.128 29458 21314 I flutter : method: POST
05-10 10:45:36.129 29458 21314 I flutter : contentType: application/json; charset=utf-8
05-10 10:45:36.129 29458 21314 I flutter : responseType: ResponseType.plain
05-10 10:45:36.129 29458 21314 I flutter : followRedirects: true
05-10 10:45:36.129 29458 21314 I flutter : connectTimeout: 10000
05-10 10:45:36.129 29458 21314 I flutter : receiveTimeout: 10000
05-10 10:45:36.129 29458 21314 I flutter : extra: {}
05-10 10:45:36.129 29458 21314 I flutter : header:
05-10 10:45:36.129 29458 21314 I flutter :   **; Path=/; Expires=Sat, 10 Apr 2021 10:12:54 GMT; HttpOnly]
05-10 10:45:36.129 29458 21314 I flutter :

I usually do

adb logcat | tee android.log

When I see an interesting log I get back to the line in the android.log.

In comment you just published you have your personal JWT, delete it here and/or logout in the app, because someone could use it to make requests

@rewhex thanks for letting me know, I appreciate security-wise thinking :)
No worries, I've anonymized the token and regenerated it with a random hmac key, so it is not directly usable but the format stays.

Birthday format is: "YYYY-MM"

I've just captured a login request.

It is a simple HTTPS POST, the password is a simple md5(plain-password)
(password here is "test", I've anonymized JWT token)

--<request>--  v  {email: ph4r05@gmail.com, password: 098f6bcd4621d373cade4e832627b4f6}
05-10 11:12:02.874 22677 22710 I flutter : --<request>handleResponse--  v  null
05-10 11:12:02.874 22677 22710 I flutter : lyt-------请求url https://eu.app.walkingpad.com/user/api/v2/login

05-10 11:12:02.874 22677 22710 I flutter : *** Request ***
05-10 11:12:02.874 22677 22710 I flutter : uri: https://eu.app.walkingpad.com/user/api/v2/login
05-10 11:12:02.874 22677 22710 I flutter : method: POST
05-10 11:12:02.875 22677 22710 I flutter : contentType: application/json; charset=utf-8
05-10 11:12:02.875 22677 22710 I flutter : responseType: ResponseType.plain
05-10 11:12:02.875 22677 22710 I flutter : followRedirects: true
05-10 11:12:02.875 22677 22710 I flutter : connectTimeout: 10000
05-10 11:12:02.875 22677 22710 I flutter : receiveTimeout: 10000
05-10 11:12:02.875 22677 22710 I flutter : extra: {}

Response:

05-10 11:12:03.418 22677 22710 I flutter : *** Response ***
05-10 11:12:03.418 22677 22710 I flutter : uri: https://eu.app.walkingpad.com/user/api/v2/login
05-10 11:12:03.419 22677 22710 I flutter : statusCode: 200
05-10 11:12:03.419 22677 22710 I flutter : headers:
05-10 11:12:03.419 22677 22710 I flutter :  connection: keep-alive
05-10 11:12:03.419 22677 22710 I flutter :  access-control-allow-credentials: true
05-10 11:12:03.419 22677 22710 I flutter :  access-control-allow-headers: *
05-10 11:12:03.419 22677 22710 I flutter :  set-cookie: user=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VyIjp7ImlkIjoxMjM0NTYsImVtYWlsIjoicGg0cjA1QGdtYWlsLmNvbSIsImRpc3RhbmNlX3VuaXQiOiJrbSIsImhlaWdodF91bml0IjoibSIsIndlaWdodF91bml0Ijoia2ciLCJiaXJ0aCI6Im5vdC10ZWxsaW5nIiwiZ2VuZGVyIjp0cnVlLCJoZWlnaHQiOjEuOCwid2VpZ2h0Ijo4MCwiZ3VpZGVfaW5mbyI6dHJ1ZX0sImV4cCI6MTYxODA0OTU3NCwiaXNzIjoiZ2VuZXJhdGUgdG9rZW4ifQ.NXqkC7EI44sQm4_xLYchuHhdwXRwPYRziRI_a6Oop-k; Path=/; Expires=Wed, 09 Jun 2021 09:12:03 GMT; HttpOnly
05-10 11:12:03.419 22677 22710 I flutter :  access-control-allow-origin: *
05-10 11:12:03.419 22677 22710 I flutter :  date: Mon, 10 May 2021 09:12:03 GMT
05-10 11:12:03.419 22677 22710 I flutter :  access-control-allow-methods: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE
05-10 11:12:03.419 22677 22710 I flutter :  vary: Accept-Encoding
05-10 11:12:03.419 22677 22710 I flutter :  strict-transport-security: max-age=15724800; includeSubDomains
05-10 11:12:03.419 22677 22710 I flutter :  content-length: 222
05-10 11:12:03.419 22677 22710 I flutter :  content-type: application/json; charset=utf-8
05-10 11:12:03.419 22677 22710 I flutter :
05-10 11:12:03.419 22677 22710 I flutter :
05-10 11:12:03.421 22677 22710 I flutter : ------cookie
05-10 11:12:03.421 22677 22710 I flutter : [user=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VyIjp7ImlkIjoxMjM0NTYsImVtYWlsIjoicGg0cjA1QGdtYWlsLmNvbSIsImRpc3RhbmNlX3VuaXQiOiJrbSIsImhlaWdodF91bml0IjoibSIsIndlaWdodF91bml0Ijoia2ciLCJiaXJ0aCI6Im5vdC10ZWxsaW5nIiwiZ2VuZGVyIjp0cnVlLCJoZWlnaHQiOjEuOCwid2VpZ2h0Ijo4MCwiZ3VpZGVfaW5mbyI6dHJ1ZX0sImV4cCI6MTYxODA0OTU3NCwiaXNzIjoiZ2VuZXJhdGUgdG9rZW4ifQ.NXqkC7EI44sQm4_xLYchuHhdwXRwPYRziRI_a6Oop-k; Path=/; Expires=Wed, 09 Jun 2021 09:12:03 GMT; HttpOnly]

Hey, thank you, i saw the api in the code, so i already grepped for walkingpad.com, i suspect it's a different API for R1 PRO.
Also i use the KS FIT app, this is what you have also?
Thank you.

And i use this one:
https://play.google.com/store/apps/details?id=com.kingsmith.xiaojin

I'll try the one you are using, i suspect they are compatible.
Thank you.

And i use this one:
https://play.google.com/store/apps/details?id=com.kingsmith.xiaojin

I'll try the one you are using, i suspect they are compatible.
Thank you.

WalkingPad app doesn't work for r1 pro, afaik

Did not take your word for it, so i tested, turns out you are correct, it doesn't work for R1 PRO :))

Recently I purchased R2 (non pro version; CN local version)
KS Fit app uses encrypted packet(so @rewhex's application didn't work https://play.google.com/store/apps/details?id=dev.rewhex.walkingpadr1)

for example, the app sent shake to R2, but real sending packet is DAEEOAU= in the bootup time.
adb logcat prints every I/O plain text and encrypted data. but idk encryption algorithm & every devices use same key or not.

Recently I purchased R2 (non pro version; CN local version)
KS Fit app uses encrypted packet(so @rewhex's application didn't work https://play.google.com/store/apps/details?id=dev.rewhex.walkingpadr1)

for example, the app sent shake to R2, but real sending packet is DAEEOAU= in the bootup time.
adb logcat prints every I/O plain text and encrypted data. but idk encryption algorithm & every devices use same key or not.

It's not encrypted, my app handles the same. It's just your phone logging base64 packet as is. My app just not accept R2 at all, and I'm not planning to support it, 'encryption' is not the case.

Well.. I just tested your app during investing packet reference.
I'm just trying to find multiple references to support this packet.
And I heard from auther of qdomyos-zwift that R2 pro packet is same as R1 pro.

Maybe China version devices have different packet protocol.
And packets of device are encrypted. decoded base64 DAEEOAU= isn't shake. it's [0x0c, 0x01, 0x04, 0x38, 0x05].

Well.. I just tested your app during investing packet reference.
I'm just trying to find multiple references to support this packet.
And I heard from auther of qdomyos-zwift that R2 pro packet is same as R1 pro.

Maybe China version devices have different packet protocol.
And packets of device are encrypted. decoded base64 DAEEOAU= isn't shake. it's [0x0c, 0x01, 0x04, 0x38, 0x05].

Do you have another variants of packets?

I got a progress after the message.
the cipher algorighm is caesar cipher. here is packet sample and handshake chain.
https://gist.github.com/d3m3vilurr/69b84ce4d57ed8c93b19c93600570394

I got a progress after the message.
the cipher algorighm is caesar cipher. here is packet sample and handshake chain.
https://gist.github.com/d3m3vilurr/69b84ce4d57ed8c93b19c93600570394

Oh, I just noticed that you have a cn version, I don't know how r1 cn version works, but r1 pro packets seems very different, for example you have readable prop names etc. R1 pro have only bytes with command type: 178, 2, 1 (for example) means "props ControlMode 1".

Can confirm that this works with the Lifespan Fitness - WalkingPad™ M2 Treadmill branded version of this walking pad. Had some issues with getting it going on Windows (probably some issues on my end), although worked perfectly fine on a Raspberry PI with Bluez installed.

rewhex commented

Just want to show some progress about creating an emulator R1 (and R2) Pro for my Android client app, as I want to sell my treadmill, on video from left to right: My client app, Telegram bot with the UI, Emulator which works like R1 Pro :)

Screen.Recording.2023-04-20.at.9.26.43.PM.mov

Hello, I really appreciate your library. may I ask, does the change_speed works on you guys?