wechat_minapp/
credential.rs1#[allow(deprecated)]
2use aes::{
3 Aes128,
4 cipher::{BlockDecryptMut, KeyIvInit, block_padding::Pkcs7, generic_array::GenericArray},
5};
6use base64::{Engine, engine::general_purpose::STANDARD};
7use cbc::Decryptor;
8use hex::encode;
9use hmac::{Hmac, Mac};
10use serde::{Deserialize, Serialize};
11use serde_json::from_slice;
12use sha2::Sha256;
13use std::collections::HashMap;
14use tracing::{debug, instrument};
15
16use crate::{
17 Result,
18 client::Client,
19 constants,
20 error::Error::InternalServer,
21 response::Response,
22 user::{User, UserBuilder},
23};
24
25type Aes128CbcDec = Decryptor<Aes128>;
26
27#[derive(Serialize, Deserialize, Clone)]
28pub struct Credential {
29 open_id: String,
30 session_key: String,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 union_id: Option<String>,
33}
34
35impl Credential {
36 pub fn open_id(&self) -> &str {
37 &self.open_id
38 }
39
40 pub fn session_key(&self) -> &str {
41 &self.session_key
42 }
43
44 pub fn union_id(&self) -> Option<&str> {
45 self.union_id.as_deref()
46 }
47
48 #[instrument(skip(self, encrypted_data, iv))]
75 pub fn decrypt(&self, encrypted_data: &str, iv: &str) -> Result<User> {
76 debug!("encrypted_data: {}", encrypted_data);
77 debug!("iv: {}", iv);
78
79 let key = STANDARD.decode(self.session_key.as_bytes())?;
80 let iv = STANDARD.decode(iv.as_bytes())?;
81 #[allow(deprecated)]
82 let decryptor = Aes128CbcDec::new(
83 &GenericArray::clone_from_slice(&key),
84 &GenericArray::clone_from_slice(&iv),
85 );
86
87 let encrypted_data = STANDARD.decode(encrypted_data.as_bytes())?;
88
89 let buffer = decryptor.decrypt_padded_vec_mut::<Pkcs7>(&encrypted_data)?;
90
91 let builder = from_slice::<UserBuilder>(&buffer)?;
92
93 debug!("user builder: {:#?}", builder);
94
95 Ok(builder.build())
96 }
97}
98
99impl std::fmt::Debug for Credential {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 f.debug_struct("Credential")
103 .field("open_id", &self.open_id)
104 .field("session_key", &"********")
105 .field("union_id", &self.union_id)
106 .finish()
107 }
108}
109
110#[derive(Deserialize)]
111pub(crate) struct CredentialBuilder {
112 #[serde(rename = "openid")]
113 open_id: String,
114 session_key: String,
115 #[serde(rename = "unionid")]
116 union_id: Option<String>,
117}
118
119impl CredentialBuilder {
120 pub(crate) fn build(self) -> Credential {
121 Credential {
122 open_id: self.open_id,
123 session_key: self.session_key,
124 union_id: self.union_id,
125 }
126 }
127}
128
129impl std::fmt::Debug for CredentialBuilder {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 f.debug_struct("CredentialBuilder")
132 .field("open_id", &self.open_id)
133 .field("session_key", &"********")
134 .field("union_id", &self.union_id)
135 .finish()
136 }
137}
138
139type HmacSha256 = Hmac<Sha256>;
140
141impl Client {
142 #[instrument(skip(self, session_key, open_id))]
145 pub async fn check_session_key(&self, session_key: &str, open_id: &str) -> Result<()> {
146 let mut mac = HmacSha256::new_from_slice(session_key.as_bytes())?;
147 mac.update(b"");
148 let hasher = mac.finalize();
149 let signature = encode(hasher.into_bytes());
150
151 let mut map = HashMap::new();
152
153 map.insert("openid", open_id.to_string());
154 map.insert("signature", signature);
155 map.insert("sig_method", "hmac_sha256".into());
156
157 let response = self
158 .request()
159 .get(constants::CHECK_SESSION_KEY_END_POINT)
160 .query(&map)
161 .send()
162 .await?;
163
164 debug!("response: {:#?}", response);
165
166 if response.status().is_success() {
167 let response = response.json::<Response<()>>().await?;
168
169 response.extract()
170 } else {
171 Err(crate::error::Error::InternalServer(response.text().await?))
172 }
173 }
174
175 #[instrument(skip(self, open_id))]
178 pub async fn reset_session_key(&self, session_key: &str, open_id: &str) -> Result<Credential> {
179 let mut mac = HmacSha256::new_from_slice(session_key.as_bytes())?;
180 mac.update(b"");
181 let hasher = mac.finalize();
182 let signature = encode(hasher.into_bytes());
183
184 let mut map = HashMap::new();
185
186 map.insert("access_token", self.access_token().await?);
187 map.insert("openid", open_id.to_string());
188 map.insert("signature", signature);
189 map.insert("sig_method", "hmac_sha256".into());
190
191 let response = self
192 .request()
193 .get(constants::RESET_SESSION_KEY_END_POINT)
194 .query(&map)
195 .send()
196 .await?;
197
198 debug!("response: {:#?}", response);
199
200 if response.status().is_success() {
201 let response = response.json::<Response<CredentialBuilder>>().await?;
202
203 let credential = response.extract()?.build();
204
205 debug!("credential: {:#?}", credential);
206
207 Ok(credential)
208 } else {
209 Err(InternalServer(response.text().await?))
210 }
211 }
212}