tcloud_im_api/api/
usersig.rs

1use crypto::{hmac::Hmac, mac::Mac, sha2::Sha256};
2use flate2::{write::ZlibEncoder, Compression};
3use serde::Serialize;
4use std::{
5    io::prelude::*,
6    time::{Duration, SystemTime, UNIX_EPOCH},
7};
8
9use crate::error::Error;
10
11#[derive(Debug, Serialize)]
12struct SigDoc {
13    #[serde(rename = "TLS.expire")]
14    expire: u64,
15    #[serde(rename = "TLS.ver")]
16    ver: String,
17    #[serde(rename = "TLS.sdkappid")]
18    sdkappid: u64,
19    #[serde(rename = "TLS.identifier")]
20    identifier: String,
21    #[serde(rename = "TLS.sig")]
22    sig: String,
23    #[serde(rename = "TLS.time")]
24    time: u64,
25    #[serde(rename = "TLS.userbuf", skip_serializing_if = "Option::is_none")]
26    user_buf: Option<String>,
27}
28
29pub fn gen_usersig(
30    sdk_appid: u64,
31    key: &str,
32    userid: &str,
33    expire: Duration,
34) -> Result<String, Error> {
35    do_gen_usersig(sdk_appid, key, userid, expire, vec![].as_ref())
36}
37
38fn do_gen_usersig(
39    sdk_appid: u64,
40    key: &str,
41    userid: &str,
42    expire: Duration,
43    user_buf: &[u8],
44) -> Result<String, Error> {
45    let curr_time = SystemTime::now()
46        .duration_since(UNIX_EPOCH)
47        .expect("please setup system timestamp")
48        .as_secs();
49    let base64_userbuf = if !user_buf.is_empty() {
50        Some(base64::encode(user_buf))
51    } else {
52        None
53    };
54
55    let sign = hmacsha256(
56        sdk_appid,
57        key,
58        userid,
59        curr_time,
60        expire.as_secs(),
61        base64_userbuf.as_ref().map(|t| t.as_str()),
62    );
63
64    let doc = SigDoc {
65        ver: "2.0".to_owned(),
66        identifier: userid.to_owned(),
67        sdkappid: sdk_appid,
68        expire: expire.as_secs(),
69        time: curr_time,
70        sig: sign,
71        user_buf: base64_userbuf,
72    };
73
74    let mut deflater = ZlibEncoder::new(Vec::new(), Compression::default());
75    deflater.write_all(serde_json::to_string(&doc)?.as_bytes())?;
76    let ret_vec = deflater.finish()?;
77    Ok(base64_url(ret_vec.as_slice()))
78}
79
80fn hmacsha256(
81    sdk_appid: u64,
82    key: &str,
83    identifier: &str,
84    curr_time: u64,
85    expire: u64,
86    user_buf: Option<&str>,
87) -> String {
88    let mut content = format!(
89        "TLS.identifier:{}\nTLS.sdkappid:{}\nTLS.time:{}\nTLS.expire:{}\n",
90        identifier, sdk_appid, curr_time, expire
91    );
92
93    if let Some(data) = user_buf {
94        content += "TLS.userbuf:";
95        content += data;
96        content += "\n";
97    }
98
99    let mut hmac = Hmac::new(Sha256::new(), key.as_bytes());
100    hmac.input(content.as_bytes());
101    base64::encode(hmac.result().code())
102}
103
104fn base64_url(bytes: &[u8]) -> String {
105    base64::encode(bytes)
106        .replace("+", "*")
107        .replace("/", "-")
108        .replace("=", "_")
109}