homegate/api/
app_id.rs

1
2use std::io::Cursor;
3
4use byteorder::{BigEndian, ReadBytesExt};
5
6use hmac::{Hmac, Mac};
7use sha2::Sha256;
8
9use crate::api::{SECRET, USER_AGENT};
10
11type HmacSha256 = Hmac<Sha256>;
12
13fn calculate_hmac(s: &str) -> String {
14    let mut h: HmacSha256 = HmacSha256::new_from_slice(&SECRET).unwrap();
15    h.update(s.as_bytes());
16    let result = h.finalize().into_bytes();
17
18
19    let b = result[result.len() - 1] & 0xF;
20    let mut buffer: Vec<u8> = vec![0; 4];
21    let mut i;
22    let mut j = 0;
23    loop {
24        i = j;
25        j = i + 1;
26        buffer[i] = result[i + b as usize];
27        if j > 3 {
28            buffer[0] = buffer[0] & 0xFF;
29            let mut rdr = Cursor::new(buffer);
30            let n = rdr.read_i32::<BigEndian>().unwrap();
31            return format!("{}", n);
32        }
33    }
34}
35
36pub fn calculate_app_id(time: &chrono::NaiveDateTime) -> String {
37    let time_millis = time.timestamp_millis() as u64;
38    let ceil = (f64::from((time_millis / 1000) as u32) / f64::from(60.0)).ceil();
39    let s = format!("{}{}{}", USER_AGENT, app_version(), ceil);
40
41    return calculate_hmac(&s);
42}
43
44pub fn app_version() -> String {
45    let sdk_version = 30;
46    return format!("Homegate/12.6.0/12060003/Android/{}", sdk_version);
47}
48
49#[cfg(test)]
50mod test {
51    
52    
53    
54
55    use crate::api::app_id::calculate_app_id;
56
57    #[test]
58    fn test_app_id() -> Result<(), std::io::Error> {
59        assert_eq!("1926888397", calculate_app_id(
60            &chrono::NaiveDateTime::new(
61                chrono::NaiveDate::from_ymd(2022, 1, 25),
62                chrono::NaiveTime::from_hms(1, 30, 56)),
63        ));
64        return Ok(());
65    }
66}