wechat_minapp/user/
credential.rs1use super::User;
2use super::user_info::{UserBuilder, UserInfo};
3#[allow(deprecated)]
4use aes::{
5 Aes128,
6 cipher::{BlockDecryptMut, KeyIvInit, block_padding::Pkcs7, generic_array::GenericArray},
7};
8use base64::{Engine, engine::general_purpose::STANDARD};
9use cbc::Decryptor;
10use hex::encode;
11use hmac::{Hmac, Mac};
12use http::Method;
13use serde::{Deserialize, Serialize};
14use serde_json::from_slice;
15use sha2::Sha256;
16use tracing::{debug, instrument};
17
18use crate::utils::{RequestBuilder, ResponseExt};
19use crate::{Result, constants};
20
21type Aes128CbcDec = Decryptor<Aes128>;
22
23#[derive(Serialize, Deserialize, Clone)]
24pub struct Credential {
25 #[serde(rename="openid")]
26 open_id: String,
27 session_key: String,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 union_id: Option<String>,
30}
31
32impl Credential {
33 pub fn open_id(&self) -> &str {
34 &self.open_id
35 }
36
37 pub fn session_key(&self) -> &str {
38 &self.session_key
39 }
40
41 pub fn union_id(&self) -> Option<&str> {
42 self.union_id.as_deref()
43 }
44
45 #[instrument(skip(self, encrypted_data, iv))]
69 pub fn decrypt(&self, encrypted_data: &str, iv: &str) -> Result<UserInfo> {
70 debug!("encrypted_data: {}", encrypted_data);
71 debug!("iv: {}", iv);
72
73 let key = STANDARD.decode(self.session_key.as_bytes())?;
74 let iv = STANDARD.decode(iv.as_bytes())?;
75 #[allow(deprecated)]
76 let decryptor = Aes128CbcDec::new(
77 &GenericArray::clone_from_slice(&key),
78 &GenericArray::clone_from_slice(&iv),
79 );
80
81 let encrypted_data = STANDARD.decode(encrypted_data.as_bytes())?;
82
83 let buffer = decryptor.decrypt_padded_vec_mut::<Pkcs7>(&encrypted_data)?;
84
85 let builder = from_slice::<UserBuilder>(&buffer)?;
86
87 debug!("user builder: {:#?}", builder);
88
89 Ok(builder.build())
90 }
91}
92
93impl std::fmt::Debug for Credential {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 f.debug_struct("Credential")
97 .field("open_id", &self.open_id)
98 .field("session_key", &"********")
99 .field("union_id", &self.union_id)
100 .finish()
101 }
102}
103
104type HmacSha256 = Hmac<Sha256>;
105
106impl User {
107 #[instrument(skip(self, session_key, open_id))]
110 pub async fn check_session_key(&self, session_key: &str, open_id: &str) -> Result<()> {
111 let mut mac = HmacSha256::new_from_slice(session_key.as_bytes())?;
112 mac.update(b"");
113 let hasher = mac.finalize();
114 let signature = encode(hasher.into_bytes());
115
116 let query = serde_json::json!({
117 "openid": open_id.to_string(),
118 "signature":signature,
119 "sig_method": "hmac_sha256".to_string()
120 });
121
122 let request = RequestBuilder::new(constants::CHECK_SESSION_KEY_END_POINT)
123 .query(query)
124 .method(Method::GET)
125 .build()?;
126
127 let client = &self.client.client;
128
129 let response = client.execute(request).await?;
130
131 debug!("response: {:#?}", response);
132 response.to_json::<()>()
133 }
134
135 #[instrument(skip(self, open_id))]
138 pub async fn reset_session_key(&self, session_key: &str, open_id: &str) -> Result<Credential> {
139 let mut mac = HmacSha256::new_from_slice(session_key.as_bytes())?;
140 mac.update(b"");
141 let hasher = mac.finalize();
142 let signature = encode(hasher.into_bytes());
143
144 let query = serde_json::json!({
145 "access_token":self.client.token().await?,
146 "openid": open_id.to_string(),
147 "signature":signature,
148 "sig_method": "hmac_sha256".to_string()
149 });
150
151 let request = RequestBuilder::new(constants::RESET_SESSION_KEY_END_POINT)
152 .query(query)
153 .method(Method::GET)
154 .build()?;
155
156 let client = &self.client.client;
157 let response = client.execute(request).await?;
158 debug!("response: {:#?}", &response);
159
160 response.to_json::<Credential>()
161 }
162}