wx_rust_open/bean/message/
wx_open_xml_message.rs1use crate::config::WxOpenConfigStorage;
21use crate::util::crypto::WxOpenCryptUtils;
22
23#[derive(Debug, Clone, Default, PartialEq, serde::Deserialize)]
28#[serde(rename = "xml")]
29pub struct WxOpenXmlMessage {
30 #[serde(rename = "AppId", default)]
32 pub app_id: Option<String>,
33 #[serde(rename = "CreateTime", default)]
35 pub create_time: Option<i64>,
36 #[serde(rename = "InfoType", default)]
39 pub info_type: Option<String>,
40 #[serde(rename = "ComponentVerifyTicket", default)]
42 pub component_verify_ticket: Option<String>,
43 #[serde(rename = "AuthorizerAppid", default)]
45 pub authorizer_appid: Option<String>,
46 #[serde(rename = "AuthorizationCode", default)]
48 pub authorization_code: Option<String>,
49 #[serde(rename = "AuthorizationCodeExpiredTime", default)]
51 pub authorization_code_expired_time: Option<i64>,
52 #[serde(rename = "PreAuthCode", default)]
54 pub pre_auth_code: Option<String>,
55 #[serde(rename = "appid", default)]
57 pub sub_app_id: Option<String>,
58 #[serde(rename = "status", default)]
60 pub status: Option<i32>,
61 #[serde(rename = "auth_code", default)]
63 pub auth_code: Option<String>,
64 #[serde(rename = "msg", default)]
66 pub msg: Option<String>,
67 #[serde(rename = "info", default)]
69 pub info: Info,
70 #[serde(rename = "taskid", default)]
72 pub task_id: Option<String>,
73 #[serde(rename = "task_status", default)]
77 pub task_status: Option<i32>,
78 #[serde(rename = "apply_status", default)]
81 pub apply_status: Option<i32>,
82 #[serde(rename = "message", default)]
84 pub message: Option<String>,
85 #[serde(rename = "dispatch_info", default)]
87 pub dispatch_info: Option<DispatchInfo>,
88 #[serde(rename = "expired", default)]
90 pub expired: Option<i64>,
91 #[serde(rename = "task_id", default)]
93 pub icp_verify_task_id: Option<String>,
94 #[serde(rename = "verify_appid", default)]
96 pub verify_app_id: Option<String>,
97 #[serde(rename = "result", default)]
99 pub result: Option<i32>,
100 #[serde(rename = "along_with_auth_result", default)]
102 pub along_with_auth_result: Option<i32>,
103 #[serde(rename = "authorizer_appid", default)]
105 pub beian_authorizer_app_id: Option<String>,
106 #[serde(rename = "beian_status", default)]
108 pub beian_status: Option<i32>,
109 #[serde(rename = "procedure_id", default)]
111 pub procedure_id: Option<String>,
112 #[serde(rename = "procedure_status", default)]
117 pub procedure_status: Option<i32>,
118 #[serde(default, skip)]
121 pub context: Option<String>,
122}
123
124#[derive(Debug, Clone, Default, PartialEq, serde::Deserialize)]
127pub struct Info {
128 #[serde(rename = "name", default)]
129 pub name: Option<String>,
130 #[serde(rename = "code", default)]
131 pub code: Option<String>,
132 #[serde(rename = "code_type", default)]
133 pub code_type: Option<i32>,
134 #[serde(rename = "legal_persona_wechat", default)]
135 pub legal_persona_wechat: Option<String>,
136 #[serde(rename = "legal_persona_name", default)]
137 pub legal_persona_name: Option<String>,
138 #[serde(rename = "component_phone", default)]
139 pub component_phone: Option<String>,
140 #[serde(rename = "wxuser", default)]
142 pub wxuser: Option<String>,
143 #[serde(rename = "idname", default)]
144 pub idname: Option<String>,
145 #[serde(rename = "unique_id", default)]
147 pub unique_id: Option<String>,
148}
149
150#[derive(Debug, Clone, Default, PartialEq, serde::Deserialize)]
152pub struct DispatchInfo {
153 #[serde(rename = "provider", default)]
155 pub provider: Option<String>,
156 #[serde(rename = "contact", default)]
158 pub contact: Option<String>,
159 #[serde(rename = "dispatch_time", default)]
161 pub dispatch_time: Option<i64>,
162}
163
164impl WxOpenXmlMessage {
165 pub fn from_xml(xml: &str) -> Result<Self, String> {
171 let xml = xml.replace("</PicList><PicList>", "");
172 quick_xml::de::from_str(&xml).map_err(|e| format!("WxOpenXmlMessage 解析失败: {e}"))
173 }
174
175 pub fn from_encrypted_xml(
181 encrypted_xml: &str,
182 config: &dyn WxOpenConfigStorage,
183 timestamp: &str,
184 nonce: &str,
185 msg_signature: &str,
186 ) -> Result<Self, String> {
187 let crypt_util = WxOpenCryptUtils::new(config)?;
188 let plain_text = crypt_util.decrypt_xml(msg_signature, timestamp, nonce, encrypted_xml)?;
189 if plain_text.trim().is_empty() {
190 return Err("解密后的xml消息内容为空,请检查加密参数是否正确".to_string());
191 }
192 let mut message = Self::from_xml(&plain_text)?;
193 message.context = Some(plain_text);
194 Ok(message)
195 }
196
197 pub fn from_encrypted_mp_xml(
205 encrypted_xml: &str,
206 config: &dyn WxOpenConfigStorage,
207 timestamp: &str,
208 nonce: &str,
209 msg_signature: &str,
210 ) -> Result<String, String> {
211 let crypt_util = WxOpenCryptUtils::new(config)?;
212 crypt_util.decrypt_xml(msg_signature, timestamp, nonce, encrypted_xml)
213 }
214}
215
216pub fn wx_mp_out_xml_message_to_encrypted_xml(
224 plain_xml: &str,
225 config: &dyn WxOpenConfigStorage,
226) -> Result<String, String> {
227 let crypt_util = WxOpenCryptUtils::new(config)?;
228 crypt_util.encrypt(plain_xml)
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234
235 #[test]
237 fn parse_verify_ticket() {
238 let xml = r#"<xml>
239 <AppId><![CDATA[wxb1234567890abcdef]]></AppId>
240 <CreateTime>1413192605</CreateTime>
241 <InfoType><![CDATA[verify_ticket]]></InfoType>
242 <ComponentVerifyTicket><![CDATA[ticket@@@6iJtQHC1]]></ComponentVerifyTicket>
243</xml>"#;
244 let m = WxOpenXmlMessage::from_xml(xml).unwrap();
245 assert_eq!(m.app_id.as_deref(), Some("wxb1234567890abcdef"));
246 assert_eq!(m.create_time, Some(1413192605));
247 assert_eq!(m.info_type.as_deref(), Some("verify_ticket"));
248 assert_eq!(
249 m.component_verify_ticket.as_deref(),
250 Some("ticket@@@6iJtQHC1")
251 );
252 assert_eq!(m.context, None);
253 }
254
255 #[test]
257 fn parse_fasteregister() {
258 let xml = r#"<xml>
259<AppId><![CDATA[wx1234567890abcdef]]></AppId>
260<CreateTime>1492747804</CreateTime>
261<InfoType><![CDATA[notify_third_fasteregister]]></InfoType>
262<appid><![CDATA[wx1234567890abcdef]]></appid>
263<status>0</status>
264<auth_code><![CDATA[queryauthcode@@@123]]></auth_code>
265<msg><![CDATA[]]></msg>
266<info><name><![CDATA[test]]></name><code><![CDATA[123456]]></code><code_type>1</code_type><legal_persona_wechat><![CDATA[wx123]]></legal_persona_wechat><legal_persona_name><![CDATA[张三]]></legal_persona_name><component_phone><![CDATA[13800000000]]></component_phone></info>
267</xml>"#;
268 let m = WxOpenXmlMessage::from_xml(xml).unwrap();
269 assert_eq!(m.info_type.as_deref(), Some("notify_third_fasteregister"));
270 assert_eq!(m.sub_app_id.as_deref(), Some("wx1234567890abcdef"));
271 assert_eq!(m.status, Some(0));
272 assert_eq!(m.auth_code.as_deref(), Some("queryauthcode@@@123"));
273 assert_eq!(m.info.name.as_deref(), Some("test"));
274 assert_eq!(m.info.code.as_deref(), Some("123456"));
275 assert_eq!(m.info.code_type, Some(1));
276 assert_eq!(m.info.legal_persona_name.as_deref(), Some("张三"));
277 }
278}