tcloud_im_api/api/
usersig.rs1use 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}