1use std::collections::{HashMap};
2use base64::Engine;
3use base64::engine::general_purpose;
4use chrono::Local;
5use crate::PayMode;
6use json::{object, JsonValue};
7use openssl::hash::MessageDigest;
8use openssl::pkey::{PKey};
9use openssl::rsa::Rsa;
10use openssl::sign::Signer;
11use urlencoding::encode;
12
13#[derive(Clone)]
14pub struct AliPay {
15 pub appid: String,
17 pub app_auth_token: String,
19 pub app_private: String,
21}
22impl AliPay {
23 pub fn http(&mut self, method: &str, biz_content: JsonValue) -> Result<JsonValue, String> {
24 let mut http = br_http::Http::new();
25 let sign = "";
26
27 let now = Local::now();
28 let timestamp = now.format("%Y-%m-%d %H:%M:%S").to_string();
29
30
31 let mut data = object! {
32 "charset":"UTF-8",
33 "method":method,
34 "app_id":self.appid.clone(),
35 "version":"1.0",
36 "sign_type":"RSA2",
37 "timestamp":timestamp,
38 "app_auth_token":self.app_auth_token.clone(),
39 "sign":sign,
40 "biz_content": biz_content,
41 };
42
43 let mut map = HashMap::new();
44 for (key, value) in data.entries() {
45 if key == "sign" {
46 continue;
47 }
48 if value.is_empty() {
49 continue;
50 }
51 map.insert(key, value);
52 }
53
54 let mut keys: Vec<_> = map.keys().cloned().collect();
55 keys.sort();
56 let mut txt = vec![];
57 for key in keys {
58 txt.push(format!("{}={}", key, map.get(&key).unwrap()));
59 }
60 let txt = txt.join("&");
61 let t = self.app_private.as_bytes().chunks(64).map(|chunk| std::str::from_utf8(chunk).unwrap_or("")).collect::<Vec<&str>>().join("\n");
62 let cart = format!("-----BEGIN PRIVATE KEY-----\n{}\n-----END PRIVATE KEY-----\n", t);
63
64 let rsa = match Rsa::private_key_from_pem(cart.as_bytes()) {
66 Ok(e) => e,
67 Err(e) => return Err(e.to_string())
68 };
69
70 let pkey = match PKey::from_rsa(rsa) {
71 Ok(e) => e,
72 Err(e) => return Err(e.to_string())
73 };
74
75 let mut signer = match Signer::new(MessageDigest::sha256(), &pkey) {
77 Ok(e) => e,
78 Err(e) => return Err(e.to_string())
79 };
80 match signer.update(txt.as_bytes()) {
81 Ok(()) => {}
82 Err(e) => return Err(e.to_string())
83 };
84 let signature = match signer.sign_to_vec() {
86 Ok(e) => e,
87 Err(e) => return Err(e.to_string())
88 };
89 data["sign"] = general_purpose::STANDARD.encode(signature).into();
91
92 let mut new_data = object! {};
93 for (key, value) in data.entries() {
94 let t = encode(value.to_string().as_str()).to_string();
95 new_data[key] = t.into();
96 }
97 data = new_data;
98 let url = "https://openapi.alipay.com/gateway.do".to_string();
99 let res = match http.post(url.as_str()).query(data).json() {
100 Ok(e) => e,
101 Err(e) => {
102 println!(">>>>>>{}", e);
103 return Err(e);
104 }
105 };
106 if res.has_key("error_response") {
107 return Err(res["error_response"]["sub_msg"].to_string());
108 }
109 let key = method.replace(".", "_");
110 let key = format!("{}_response", key);
111 let data = res[key].clone();
112 if data.has_key("code") {
113 if data["code"] != "10000" {
114 Err(data["sub_msg"].to_string())
115 } else {
116 Ok(data)
117 }
118 } else {
119 Err(data.to_string())
120 }
121 }
122}
123impl PayMode for AliPay {
124 fn login(&mut self, code: &str) -> Result<JsonValue, String> {
125 let res = self.http("alipay.system.oauth.token", object! {
126 grant_type:"authorization_code",
127 code:code
128 })?;
129 Ok(res)
130 }
131
132 fn auth(&mut self, code: &str) -> Result<JsonValue, String> {
133 let res = match self.http("alipay.open.auth.token.app", object! {
134 grant_type:"authorization_code",
135 code:code
136 }) {
137 Ok(e) => e,
138 Err(e) => {
139 println!("Err: {:#}", e);
140 return Err(e);
141 }
142 };
143 println!("{:#}", res);
149 Ok(object! {})
150 }
151
152 fn jsapi(
153 &mut self,
154 _sub_mchid: &str,
155 out_trade_no: &str,
156 description: &str,
157 total_fee: f64,
158 _notify_url: &str,
159 sp_openid: &str,
160 ) -> Result<JsonValue, String> {
161 self.app_auth_token = "202503BB5aba0791592f4cd9966ba090d36dfX11".to_string();
162 match self.http("alipay.trade.create", object! {
163 out_trade_no:out_trade_no,
164 total_amount:total_fee,
165 subject:description,
166 product_code:"JSAPI_PAY",
167 op_app_id:"2088541900270114",
168 buyer_open_id:sp_openid
169 }) {
170 Ok(e) => {
171 println!("{:#}", e);
172 }
173 Err(e) => {
174 println!("Err: {:#}", e);
175 return Err(e);
176 }
177 };
178
179
180 Ok(object! {})
181 }
182
183 fn close(&mut self, _out_trade_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
184 todo!()
185 }
186
187 fn pay_query(&mut self, _out_trade_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
188 todo!()
189 }
190
191 fn pay_notify(&mut self, _nonce: &str, _ciphertext: &str, _associated_data: &str) -> Result<JsonValue, String> {
192 todo!()
193 }
194
195 fn refund(&mut self, _sub_mchid: &str, _out_trade_no: &str, _transaction_id: &str, _out_refund_no: &str, _amount: f64, _total: f64, _currency: &str) -> Result<JsonValue, String> {
196 todo!()
197 }
198
199 fn refund_notify(&mut self, _nonce: &str, _ciphertext: &str, _associated_data: &str) -> Result<JsonValue, String> {
200 todo!()
201 }
202
203 fn refund_query(&mut self, _out_refund_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
204 todo!()
205 }
206}