first commit
This commit is contained in:
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal 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?
|
||||
12
package.json
Normal file
12
package.json
Normal 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
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
requests
|
||||
40
test.py
Normal file
40
test.py
Normal 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
253
token_extractor.py
Normal 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
172
笔记.txt
Normal 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
|
||||
---------
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user