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