Created
August 12, 2026 00:48
-
-
Save OlivierLaflamme/24250c6beac5de4bf24c7f1c6fec0229 to your computer and use it in GitHub Desktop.
validate.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| """ | |
| python3 validate.py <email> <password> [serial_number] | |
| """ | |
| import hashlib | |
| import json | |
| import sys | |
| import time | |
| import uuid | |
| from curl_cffi import requests as cffi_requests | |
| BASE_URL = "https://global-robot-api.unitree.com/" | |
| APP_SIGN_SECRET = "XyvkwK45hp5PHfA8" | |
| def make_headers(token="", device_type="G1"): | |
| ts = str(int(time.time() * 1000)) | |
| nonce = uuid.uuid4().hex | |
| sign = hashlib.md5(f"{APP_SIGN_SECRET}{ts}{nonce}".encode()).hexdigest() | |
| return { | |
| "Content-Type": "application/x-www-form-urlencoded", | |
| "DeviceId": "Google/Google/Pixel 8 Pro/husky/14/34", | |
| "DevicePlatform": "Android", | |
| "DeviceModel": "Pixel 8 Pro", | |
| "SystemVersion": "34", | |
| "AppVersion": "1.11.6", | |
| "AppLocale": "en_US", | |
| "Channel": "UMENG_CHANNEL", | |
| "AppTimezone": "UTC", | |
| "AppTimestamp": ts, | |
| "AppNonce": nonce, | |
| "AppSign": sign, | |
| "AppName": device_type, | |
| "Token": token, | |
| "User-Agent": ( | |
| "Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro Build/AD1A.240905.004; wv) " | |
| "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.70 " | |
| "Mobile Safari/537.36" | |
| ), | |
| } | |
| def login(session, email, password): | |
| resp = session.post( | |
| BASE_URL + "login/email", | |
| data={"email": email, "password": hashlib.md5(password.encode()).hexdigest()}, | |
| headers=make_headers(), | |
| ) | |
| result = resp.json() | |
| if result.get("code") != 100: | |
| print(f"Login failed: {result}") | |
| sys.exit(1) | |
| return result["data"]["accessToken"] | |
| def list_devices(session, token): | |
| resp = session.get( | |
| BASE_URL + "device/bind/list", | |
| headers=make_headers(token=token), | |
| ) | |
| result = resp.json() | |
| if result.get("code") != 100: | |
| print(f"list_devices failed: {result}") | |
| sys.exit(1) | |
| return result.get("data", []) | |
| def main(): | |
| if len(sys.argv) < 3: | |
| print(f"Usage: {sys.argv[0]} <email> <password> [serial_number]") | |
| sys.exit(1) | |
| email = sys.argv[1] | |
| password = sys.argv[2] | |
| target_sn = sys.argv[3] if len(sys.argv) > 3 else None | |
| session = cffi_requests.Session(impersonate="chrome120") | |
| print(f"[*] Logging in as {email}...") | |
| token = login(session, email, password) | |
| print(f"[+] Login OK") | |
| print(f"[*] Fetching bound devices...") | |
| devices = list_devices(session, token) | |
| if not devices: | |
| print("[-] No devices bound to this account") | |
| sys.exit(1) | |
| print(f"[+] Found {len(devices)} device(s):\n") | |
| for dev in devices: | |
| sn = dev.get("sn", "?") | |
| key = dev.get("key", "") or dev.get("gcm_key", "") | |
| alias = dev.get("alias", "") | |
| series = dev.get("series", "") | |
| model = dev.get("model", "") | |
| online = dev.get("online", "?") | |
| marker = " <<<" if target_sn and sn == target_sn else "" | |
| print(f" SN: {sn}{marker}") | |
| print(f" Alias: {alias}") | |
| print(f" Series: {series}") | |
| print(f" Model: {model}") | |
| print(f" Key: {key}") | |
| print(f" Online: {online}") | |
| print() | |
| if target_sn and sn == target_sn: | |
| if key: | |
| print(f"[+] AES-128 key for {sn}: {key}") | |
| else: | |
| print(f"[-] No key returned for {sn}") | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment