first commit

This commit is contained in:
编码猿
2024-09-27 01:02:47 +08:00
commit 008f8d55e0
7 changed files with 502 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

1
.pydio Normal file
View File

@@ -0,0 +1 @@
72b23aef-badd-4a65-8020-b36e0310c36c

12
package.json Normal file
View File

@@ -0,0 +1,12 @@
{
"name": "token_extractor",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
requests

40
test.py Normal file
View File

@@ -0,0 +1,40 @@
# 控制米家吸顶灯
from miio.yeelight import Yeelight
ip='192.168.31.24'
token='9264fdba5c6225ea4df82641c17bcb0d'
s = Yeelight(ip=ip, token=token)
print(s.on())
print(s.set_brightness(10))
# 控制窗帘
# from miio.curtain_youpin import CurtainMiot, CurtainStatus
#
# ip='192.168.31.69'
# token='3da5703ea963b4b83c8a7a9213284ce9'
# x = CurtainMiot(ip=ip, token=token)
# print(x.info())
# # 设置窗帘打开的百分比
# print(x.set_target_position(100))
# 控制台灯
# from miio.philips_rwread import PhilipsRwread
# ip='192.168.31.250'
# token='a806248c4a754aa1af8d101ac0c742ca'
# x = PhilipsRwread(ip=ip, token=token)
# # print(x.send_handshake())
# print(x.set_brightness(80))
# from miio.chuangmi_plug import ChuangmiPlug
#
# ip='192.168.31.24'
# token='9264fdba5c6225ea4df82641c17bcb0d'
# d = ChuangmiPlug(ip=ip, token=token)
#
# print(d.status())
# # print(d.info())
# d.off() # 关闭书房灯
# # d.on() # 打开书房灯

253
token_extractor.py Normal file
View File

@@ -0,0 +1,253 @@
import base64
import hashlib
import hmac
import json
import os
import random
import time
from sys import platform
import requests
if platform != "win32":
import readline
class XiaomiCloudConnector:
def __init__(self, username, password):
self._username = username
self._password = password
self._agent = self.generate_agent()
self._device_id = self.generate_device_id()
self._session = requests.session()
self._sign = None
self._ssecurity = None
self._userId = None
self._cUserId = None
self._passToken = None
self._location = None
self._code = None
self._serviceToken = None
def login_step_1(self):
url = "https://account.xiaomi.com/pass/serviceLogin?sid=xiaomiio&_json=true"
headers = {
"User-Agent": self._agent,
"Content-Type": "application/x-www-form-urlencoded"
}
cookies = {
"userId": self._username
}
response = self._session.get(url, headers=headers, cookies=cookies)
valid = response.status_code == 200 and "_sign" in self.to_json(response.text)
if valid:
self._sign = self.to_json(response.text)["_sign"]
return valid
def login_step_2(self):
url = "https://account.xiaomi.com/pass/serviceLoginAuth2"
headers = {
"User-Agent": self._agent,
"Content-Type": "application/x-www-form-urlencoded"
}
fields = {
"sid": "xiaomiio",
"hash": hashlib.md5(str.encode(self._password)).hexdigest().upper(),
"callback": "https://sts.api.io.mi.com/sts",
"qs": "%3Fsid%3Dxiaomiio%26_json%3Dtrue",
"user": self._username,
"_sign": self._sign,
"_json": "true"
}
response = self._session.post(url, headers=headers, params=fields)
valid = response is not None and response.status_code == 200
if valid:
json_resp = self.to_json(response.text)
valid = "ssecurity" in json_resp and len(str(json_resp["ssecurity"])) > 4
if valid:
self._ssecurity = json_resp["ssecurity"]
self._userId = json_resp["userId"]
self._cUserId = json_resp["cUserId"]
self._passToken = json_resp["passToken"]
self._location = json_resp["location"]
self._code = json_resp["code"]
else:
if "notificationUrl" in json_resp:
print("Two factor authentication required, please use following url and restart extractor:")
print(json_resp["notificationUrl"])
print()
return valid
def login_step_3(self):
headers = {
"User-Agent": self._agent,
"Content-Type": "application/x-www-form-urlencoded"
}
response = self._session.get(self._location, headers=headers)
if response.status_code == 200:
self._serviceToken = response.cookies.get("serviceToken")
return response.status_code == 200
def login(self):
self._session.cookies.set("sdkVersion", "accountsdk-18.8.15", domain="mi.com")
self._session.cookies.set("sdkVersion", "accountsdk-18.8.15", domain="xiaomi.com")
self._session.cookies.set("deviceId", self._device_id, domain="mi.com")
self._session.cookies.set("deviceId", self._device_id, domain="xiaomi.com")
if self.login_step_1():
if self.login_step_2():
if self.login_step_3():
return True
else:
print("Unable to get service token.")
else:
print("Invalid login or password.")
else:
print("Invalid username.")
return False
def get_devices(self, country):
url = self.get_api_url(country) + "/home/device_list"
params = {
"data": '{"getVirtualModel":false,"getHuamiDevices":0}'
}
return self.execute_api_call(url, params)
def get_beaconkey(self, country, did):
url = self.get_api_url(country) + "/v2/device/blt_get_beaconkey"
params = {
"data": '{"did":"' + did + '","pdid":1}'
}
return self.execute_api_call(url, params)
def execute_api_call(self, url, params):
headers = {
"Accept-Encoding": "gzip",
"User-Agent": self._agent,
"Content-Type": "application/x-www-form-urlencoded",
"x-xiaomi-protocal-flag-cli": "PROTOCAL-HTTP2"
}
cookies = {
"userId": str(self._userId),
"yetAnotherServiceToken": str(self._serviceToken),
"serviceToken": str(self._serviceToken),
"locale": "en_GB",
"timezone": "GMT+02:00",
"is_daylight": "1",
"dst_offset": "3600000",
"channel": "MI_APP_STORE"
}
millis = round(time.time() * 1000)
nonce = self.generate_nonce(millis)
signed_nonce = self.signed_nonce(nonce)
signature = self.generate_signature(url.replace("/app", ""), signed_nonce, nonce, params)
fields = {
"signature": signature,
"_nonce": nonce,
"data": params["data"]
}
response = self._session.post(url, headers=headers, cookies=cookies, params=fields)
if response.status_code == 200:
return response.json()
return None
def get_api_url(self, country):
return "https://" + ("" if country == "cn" else (country + ".")) + "api.io.mi.com/app"
def signed_nonce(self, nonce):
hash_object = hashlib.sha256(base64.b64decode(self._ssecurity) + base64.b64decode(nonce))
return base64.b64encode(hash_object.digest()).decode('utf-8')
@staticmethod
def generate_nonce(millis):
nonce_bytes = os.urandom(8) + (int(millis / 60000)).to_bytes(4, byteorder='big')
return base64.b64encode(nonce_bytes).decode()
@staticmethod
def generate_agent():
agent_id = "".join(map(lambda i: chr(i), [random.randint(65, 69) for _ in range(13)]))
return f"Android-7.1.1-1.0.0-ONEPLUS A3010-136-{agent_id} APP/xiaomi.smarthome APPV/62830"
@staticmethod
def generate_device_id():
return "".join(map(lambda i: chr(i), [random.randint(97, 122) for _ in range(6)]))
@staticmethod
def generate_signature(url, signed_nonce, nonce, params):
signature_params = [url.split("com")[1], signed_nonce, nonce]
for k, v in params.items():
signature_params.append(f"{k}={v}")
signature_string = "&".join(signature_params)
signature = hmac.new(base64.b64decode(signed_nonce), msg=signature_string.encode(), digestmod=hashlib.sha256)
return base64.b64encode(signature.digest()).decode()
@staticmethod
def to_json(response_text):
return json.loads(response_text.replace("&&&START&&&", ""))
def print_tabbed(value, tab):
print(" " * tab + value)
def print_entry(key, value, tab):
if value:
print_tabbed(f'{key + ":": <10}{value}', tab)
servers = ["cn", "de", "us", "ru", "tw", "sg", "in", "i2"]
servers_str = ", ".join(servers)
print("Username (email or user ID):")
username = input()
print("Password:")
password = input()
print(f"Server (one of: {servers_str}) Leave empty to check all available:")
server = input()
while server not in ["", *servers]:
print(f"Invalid server provided. Valid values: {servers_str}")
print("Server:")
server = input()
print()
if not server == "":
servers = [server]
connector = XiaomiCloudConnector(username, password)
print("Logging in...")
logged = connector.login()
if logged:
print("Logged in.")
print()
for current_server in servers:
devices = connector.get_devices(current_server)
if devices is not None:
if len(devices["result"]["list"]) == 0:
print(f"No devices found for server \"{current_server}\".")
continue
print(f"Devices found for server \"{current_server}\":")
for device in devices["result"]["list"]:
print_tabbed("---------", 3)
if "name" in device:
print_entry("NAME", device["name"], 3)
if "did" in device:
print_entry("ID", device["did"], 3)
if "blt" in device["did"]:
beaconkey = connector.get_beaconkey(current_server, device["did"])
if beaconkey and "result" in beaconkey and "beaconkey" in beaconkey["result"]:
print_entry("BLE KEY", beaconkey["result"]["beaconkey"], 3)
if "localip" in device:
print_entry("IP", device["localip"], 3)
if "token" in device:
print_entry("TOKEN", device["token"], 3)
if "model" in device:
print_entry("MODEL", device["model"], 3)
print_tabbed("---------", 3)
print()
else:
print("Unable to get devices.")
else:
print("Unable to log in.")
print()
print("Press ENTER to finish")
input()

172
笔记.txt Normal file
View File

@@ -0,0 +1,172 @@
---------
NAME: 台灯
ID: 244045663
IP: 192.168.31.250
TOKEN: a806248c4a754aa1af8d101ac0c742ca
MODEL: philips.light.sread3
---------
NAME: 客厅灯
ID: 317886303
IP: 192.168.31.140
TOKEN: ca897b4739938a9f03743ad825fb6980
MODEL: yeelink.light.ceiling21
---------
NAME: 书房灯
ID: 360170570
IP: 192.168.31.24
TOKEN: 9264fdba5c6225ea4df82641c17bcb0d
MODEL: yeelink.light.ceiling23
---------
NAME: 卧室灯
ID: 393790814
IP: 192.168.31.251
TOKEN: fe3f0b13f767f864c58516da753e3eec
MODEL: yeelink.light.ceiling22
---------
NAME: 书房夜灯
ID: blt.3.16hdeevig5c00
BLE KEY: 6d047ee3eb4e14fe7b8141300c3de696
TOKEN: f814990797b78ecf5a90b533
MODEL: yeelink.light.nl1
---------
NAME: 过道夜灯
ID: blt.3.16hdgfe1s5o00
BLE KEY: 1811a5b2645adf0a296c5a20f990b2a1
TOKEN: 7c68ebc0252ae1e0cf5eeb9b
MODEL: yeelink.light.nl1
---------
NAME: 路由器
ID: miwifi.71459f2f-4990-8254-5edc-8968cb80c70b
TOKEN: Ybsitd+7vNu1ewTb79oNRAFhH0F4m7BgeJMJydOb8f8=
MODEL: xiaomi.router.rm1800
---------
NAME: 客厅环境灯
ID: 1021927010
TOKEN: 09acebbf30774781c42639dfba0da6bb
MODEL: zimi.switch.dhkg02
---------
NAME: 小乖
ID: 1023017928
IP: 192.168.31.56
TOKEN: 4a5631494371736f734c696e4b497834
MODEL: dreame.vacuum.p2041
---------
NAME: 厕所灯
ID: 1023534550
IP: 112.32.24.238
TOKEN: ab60e7852342bb2fa2878435c4da0ad0
MODEL: zimi.switch.dhkg01
---------
NAME: 背景墙
ID: 1023583056
TOKEN: c28c082025f113fd5ecc8707e0475978
MODEL: zimi.switch.dhkg02
---------
NAME: 过道环境灯
ID: 1023977850
IP: 112.32.22.196
TOKEN: 8a3c00326bdd316d0f961cae1b028fe9
MODEL: zimi.switch.dhkg02
---------
NAME: 摄像头
ID: 1024903226
IP: 192.168.31.104
TOKEN: 726853767149764f663836745665666a
MODEL: isa.camera.hlc7
---------
NAME: 卧室环境灯
ID: 1043617831
TOKEN: 02a994f896ccee5ae9b46bcef83f031f
MODEL: isa.switch.kg03hl
---------
NAME: 四面八方
ID: 247969539
IP: 192.168.31.178
TOKEN: b1c57de5fbc8badf5594c5c84f7c187f
MODEL: midjd6.fridge.v1
---------
NAME: 洗碗机
ID: 248198501
IP: 192.168.31.15
TOKEN: 23a9e26128dfac7107b68f5baca1ded1
MODEL: viomi.dishwasher.m02
---------
NAME: 窗帘
ID: 358904559
IP: 192.168.31.69
TOKEN: 3da5703ea963b4b83c8a7a9213284ce9
MODEL: lumi.curtain.hmcn01
---------
NAME: 卧室窗帘
ID: 359677862
IP: 192.168.31.7
TOKEN: 057968299e569f032f4cecd0129fcefd
MODEL: lumi.curtain.hmcn01
---------
NAME: 甩甩
ID: 360186790
IP: 192.168.31.107
TOKEN: ada7f667f5b1f579715f9a4277eb3d83
MODEL: minij.washer.v11
---------
NAME: 饭饭
ID: 392783495
IP: 192.168.31.151
TOKEN: 824c2955bdcf54755715b7176713fa02
MODEL: chunmi.cooker.normalcd2
---------
NAME: 小爱音箱
ID: 425451131
IP: 192.168.31.135
TOKEN: 4431684a4539775a624c5a446d58784b
MODEL: xiaomi.wifispeaker.lx06
---------
NAME: 风扇
ID: 426805939
IP: 192.168.31.112
TOKEN: cb141f1a71c2c1693a11482ac2d8fc9c
MODEL: dmaker.fan.1e
---------
NAME: 小爱音箱2
ID: 445641071
IP: 192.168.31.9
TOKEN: 6a6568617734576e533676693362326c
MODEL: xiaomi.wifispeaker.l7a
---------
NAME: 牙刷1
ID: blt.3.16i6kptvolk00
BLE KEY: fb69fe3670def89ac078baacFFFFFFFF
TOKEN: 7065a93b675bdcd3767c02c6
MODEL: soocare.toothbrush.m1s
---------
NAME: 牙刷2
ID: blt.3.16i6l6cjclk00
BLE KEY: 42e91c130688d510f23b9c6aFFFFFFFF
TOKEN: 86f496b48e80491d439d88fe
MODEL: soocare.toothbrush.m1s
---------
NAME: 大门传感器
ID: blt.3.16o8olgdsls00
BLE KEY: fa7272f3320bd39ad37641f4a0a364cb
IP: 39.144.34.159
TOKEN: a50f44781545ed0c0a6295e9
MODEL: isa.magnet.dw2hl
---------
NAME: 卫生间传感器
ID: blt.3.17eqndfv45k01
BLE KEY: f9a1b4cc01fb4aac715b2b22a3d6e3e6
IP: 39.144.34.159
TOKEN: 2673fd6035c2579717f4d0b8
MODEL: lumi.motion.bmgl01
---------
NAME: 空调
ID: ir.1427929297838354432
MODEL: miir.aircondition.ir02
---------
NAME: 电视
ID: ir.1429160518148894720
MODEL: miir.tvbox.ir01
---------