diff --git a/cloud.py b/cloud.py index 5e39b1d..96db23d 100644 --- a/cloud.py +++ b/cloud.py @@ -127,6 +127,9 @@ class MideaCloud: data.update({ "udpid": udp_id }) + + print(data) + response = await self._api_request( endpoint="/v1/iot/secure/getToken", data=data diff --git a/midea.py b/midea.py index a1a93a4..1b4f6f3 100644 --- a/midea.py +++ b/midea.py @@ -16,57 +16,57 @@ async def test(): devices = discover.discover() if len(devices) > 0: - for device_id in devices: - token = "702b9dfc3ac6c82979986ee3a053a76f75f9e9c763ce5c25af5c2cc982f797a9409adff3745e23fee3a464d745e005c839efb0b84082acc962e59ab8683e0299" - key = "52b2feee353841588994e630dcb59819ec71ce1ffacb48628f4f436f5c54f11e" + # for device_id in devices: + # token = "702b9dfc3ac6c82979986ee3a053a76f75f9e9c763ce5c25af5c2cc982f797a9409adff3745e23fee3a464d745e005c839efb0b84082acc962e59ab8683e0299" + # key = "52b2feee353841588994e630dcb59819ec71ce1ffacb48628f4f436f5c54f11e" - device_info = devices[device_id] + # device_info = devices[device_id] - dev = device.MiedaDevice( - name="", - device_id=device_id, - device_type=225, - ip_address=device_info['ip_address'], - port=device_info['port'], - token=token, - key=key, - protocol=3, - model=device_info['model'], - attributes={} - ) + # dev = device.MiedaDevice( + # name="", + # device_id=device_id, + # device_type=225, + # ip_address=device_info['ip_address'], + # port=device_info['port'], + # token=token, + # key=key, + # protocol=3, + # model=device_info['model'], + # attributes={} + # ) - if dev.connect(False): - print("success") - else: - print("fail") + # if dev.connect(False): + # print("success") + # else: + # print("fail") - # if await cl.login(): - # for device_id in devices: - # keys = await cl.get_keys(device_id) + if await cl.login(): + for device_id in devices: + keys = await cl.get_keys(device_id) - # for k in keys: - # token = keys[k]['token'] - # key = keys[k]['key'] + for k in keys: + token = keys[k]['token'] + key = keys[k]['key'] - # device_info = devices[device_id] + device_info = devices[device_id] - # dev = device.MiedaDevice( - # name="", - # device_id=device_id, - # device_type=225, - # ip_address=device_info['ip_address'], - # port=device_info['port'], - # token=token, - # key=key, - # protocol=3, - # model=device_info['model'], - # attributes={} - # ) + dev = device.MiedaDevice( + name="", + device_id=device_id, + device_type=225, + ip_address=device_info['ip_address'], + port=device_info['port'], + token=token, + key=key, + protocol=3, + model=device_info['model'], + attributes={} + ) - # if dev.connect(False): - # return dev + if dev.connect(False): + return dev dev = asyncio.run(test()) diff --git a/security.py b/security.py index 09dd3d5..51b990f 100644 --- a/security.py +++ b/security.py @@ -59,6 +59,8 @@ class CloudSecurity: @staticmethod def get_udp_id(appliance_id, method=0): + print() + if method == 0: bytes_id = bytes(reversed(appliance_id.to_bytes(8, "big"))) elif method == 1: @@ -67,10 +69,22 @@ class CloudSecurity: bytes_id = appliance_id.to_bytes(6, "little") else: return None + + print(bytes_id) + data = bytearray(sha256(bytes_id).digest()) + + print(data) + for i in range(0, 16): data[i] ^= data[i + 16] - return data[0: 16].hex() + + hex = data[0: 16].hex() + + print(hex) + print() + + return hex def set_aes_keys(self, key, iv): if isinstance(key, str): diff --git a/src/cloud.rs b/src/cloud.rs index 0df4150..2d72eff 100644 --- a/src/cloud.rs +++ b/src/cloud.rs @@ -239,18 +239,38 @@ impl Cloud { } pub async fn keys(&self, device_id: u64) -> Result<(String, String)> { - for method in [2] { + for method in [1, 2] { let udp_id = CloudSecurity::udp_id(device_id, method); + // 1: "a79479839b272432f3bbf971f9faed30" + // 2: "a153e4273b29c04db85763c739d45203" + let mut data = self.make_general_data(); data.insert("udpid".to_string(), udp_id.clone()); + // { + // 'appVersion': '3.0.2', + // 'src': '10', + // 'format': '2', + // 'stamp': '20230925115743', + // 'platformId': '1', + // 'deviceId': 'c1bdb9d159aa18fe', + // 'reqId': '3e593c7a186f25ccca0d010d4316af0d', + // 'uid': '4c48146bdedaca956c465d53cf7dd9a3', + // 'clientType': '1', + // 'appId': '1010', + // 'udpid': '53c18d6f4682867654bee60c9ea047f4' + // } + let response = Response::from_str( &self .api_request("/v1/iot/secure/getToken", to_string(&data)?) .await?, )?; + // '76697C9A0685778C6B4F487A70497F4DB3CDD2C0949138B5BA798DADC5AE0712ECF6C3559C7EE68B96B2BB2DC140CF6172D9F1587065D4A536A75D492031E22E' + // '025f9ff7bd3c4aceb1e559ab13d5e73f6fb2358e2bcf4bb883ab62225d6b9d2d' + for token in response.token_list() { if token.udpId == udp_id { return Ok(( diff --git a/src/cloud_security.rs b/src/cloud_security.rs index 9fd9601..f6d58fb 100644 --- a/src/cloud_security.rs +++ b/src/cloud_security.rs @@ -94,14 +94,14 @@ impl CloudSecurity { let bytes_id: Vec = match method { 0 => device_id.to_be_bytes().into_iter().rev().collect(), 1 => { - let mut v = device_id.to_be_bytes().to_vec(); - v.truncate(6); + let b = device_id.to_be_bytes(); + let v = b[2..8].to_vec(); v } 2 => { - let mut v = device_id.to_le_bytes().to_vec(); - v.truncate(6); + let b = device_id.to_le_bytes(); + let v = b[0..6].to_vec(); v } @@ -109,19 +109,22 @@ impl CloudSecurity { _ => return String::new(), }; - let mut data = Sha256::digest(&bytes_id); + let data = Sha256::digest(&bytes_id); + let mut v: Vec = data.into_iter().collect(); for i in 0..16 { - data[i] ^= data[i + 16]; + v[i] ^= v[i + 16]; } - let mut v: Vec = data.into_iter().collect(); v.truncate(16); - v.iter() + let hex = v + .iter() .map(|b| format!("{b:02x}")) .collect::>() - .join("") + .join(""); + + hex } } @@ -154,4 +157,20 @@ mod test { "ac57663c18c81ad0423edb235d5b1059d792c2a18d5fad70a83a4afa92affabb" ); } + + #[test] + fn udp_id() { + const DEVICE_ID: u64 = 152832116426242; + + const UDP: [&str; 2] = [ + "53c18d6f4682867654bee60c9ea047f4", + "a153e4273b29c04db85763c739d45203", + ]; + + for method in [1, 2] { + let res = CloudSecurity::udp_id(DEVICE_ID, method); + + assert_eq!(res, UDP[method as usize - 1]); + } + } } diff --git a/src/device.rs b/src/device.rs index 7a4f231..ab964c8 100644 --- a/src/device.rs +++ b/src/device.rs @@ -64,11 +64,6 @@ impl Device { .security .encode_8370(&self.token, MsgType::HANDSHAKE_REQUEST)?; - const PY_REQUEST :&[u8;72] = b"\x83p\x00@ \x00\x00\x00p+\x9d\xfc:\xc6\xc8)y\x98n\xe3\xa0S\xa7ou\xf9\xe9\xc7c\xce\\%\xaf\\,\xc9\x82\xf7\x97\xa9@\x9a\xdf\xf3t^#\xfe\xe3\xa4d\xd7E\xe0\x05\xc89\xef\xb0\xb8@\x82\xac\xc9b\xe5\x9a\xb8h>\x02\x99"; - - // assert_eq!(request, PY_REQUEST); - - println!("writing request to stream: {request:?}"); self.socket.write(&request)?; let mut buffer = [0; 512]; @@ -135,20 +130,6 @@ mod test { Ok(()) } - #[tokio::test] - async fn connect_rust_token() -> Result<()> { - let devices = Startup::discover().await?; - - const TOKEN: &str = "702b9dfc3ac6c82979986ee3a053a76f75f9e9c763ce5c25af5c2cc982f797a9409adff3745e23fee3a464d745e005c839efb0b84082acc962e59ab8683e0299"; - const KEY: &str = "52b2feee353841588994e630dcb59819ec71ce1ffacb48628f4f436f5c54f11e"; - - for device_info in devices { - Device::connect(device_info, TOKEN, KEY)?; - } - - Ok(()) - } - #[tokio::test] #[serial] async fn full_flow() -> Result<()> {