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