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}