use chrono::Local;
use crate::{client::{APIClient}, request::{RequestType, Method, LabraRequest}, errors::LabraError, session::{SimpleStorage, SessionStore}, RequestMethod, LabradorResult, get_nonce_str, RequestParametersHolder, cfg_if};
use std::collections::{BTreeMap};
use std::fs;
use std::sync::Arc;
use dashmap::{DashMap};
use serde::Serialize;
use crate::alipay::method::AlipayMethod;
cfg_if! {if #[cfg(feature = "openssl-crypto")]{
use openssl::hash::{hash, MessageDigest};
use openssl::nid::Nid;
use openssl::x509::{X509, X509NameEntries};
}}
cfg_if! {if #[cfg(not(feature = "openssl-crypto"))]{
use x509_parser::parse_x509_certificate;
use x509_parser::x509::X509Name;
}}
mod request;
mod response;
mod method;
#[allow(unused)]
mod constants;
pub use request::*;
pub use response::*;
use crate::alipay::constants::{ENCRYPT_TYPE_AES, FORMAT_JSON, SIGN_TYPE_RSA2};
use crate::md5::md5;
use crate::prp::PrpCrypto;
#[derive(Debug, Clone)]
pub struct AlipayClient<T: SessionStore> {
api_client: APIClient<T>,
encrypt_type: String,
use_cert: bool,
format: String,
sign_type: String,
charset: String,
encrypt_key: Option<String>,
private_key: Option<String>,
alipay_public_key: Option<String>,
app_cert: Option<String>,
alipay_public_cert: Option<String>,
alipay_root_cert: Option<String>,
cache_certs: Arc<DashMap<String, String>>,
}
pub trait AlipayResponse {
fn set_sub_code(&mut self, sub_code: String);
fn set_code(&mut self, code: String);
fn get_body(&self) -> String;
fn set_body(&mut self, body: String);
fn get_sub_code(&self) -> String;
fn get_code(&self) -> String;
fn get_sign(&self) -> String;
fn get_alipay_cert_sn(&self) -> String;
fn is_success(&self) -> bool {
self.get_sub_code().is_empty()
}
fn set_msg(&mut self, msg: String);
fn set_sub_msg(&mut self, sub_msg: String);
fn get_sub_msg(&self) -> String;
fn get_msg(&self) -> String;
}
pub trait AlipayRequest<T: Serialize> {
fn get_api_method_name(&self) -> AlipayMethod;
fn get_text_params(&self) -> BTreeMap<String, String> {
BTreeMap::default()
}
fn get_api_version(&self) -> String;
fn get_terminal_type(&self) -> String;
fn get_terminal_info(&self) -> String;
fn get_prod_code(&self) -> String;
fn get_notify_url(&self) -> String;
fn get_return_url(&self) -> String;
fn is_need_encrypt(&self) -> bool;
fn get_biz_content(self) -> String;
fn get_biz_model(&self) -> Option<&T>{
None
}
}
#[allow(unused)]
impl <T: SessionStore> AlipayClient<T> {
pub fn new<Q: Into<String> + Clone>(app_key: Q, sandbox: bool) -> AlipayClient<SimpleStorage> {
let url = if sandbox {
"https://openapi.alipaydev.com/gateway.do"
} else {
"https://openapi.alipay.com/gateway.do"
};
let api_client = APIClient::<SimpleStorage>::new::<Q, String, String>(app_key.clone(), "".to_string(), url.to_owned());
AlipayClient {
api_client,
encrypt_type: ENCRYPT_TYPE_AES.to_string(),
use_cert: false,
format: FORMAT_JSON.to_string(),
sign_type: SIGN_TYPE_RSA2.to_string(),
charset: constants::CHARSET_UTF8.to_string(),
encrypt_key: None,
private_key: None,
alipay_public_key: None,
app_cert: None,
alipay_public_cert: None,
alipay_root_cert: None,
cache_certs: Arc::new(DashMap::new())
}
}
pub fn from_session<Q: Into<String> + Clone>(app_key: Q, session: T, sandbox: bool) -> AlipayClient<T> {
let url = if sandbox {
"https://openapi.alipaydev.com/gateway.do"
} else {
"https://openapi.alipay.com/gateway.do"
};
AlipayClient {
api_client: APIClient::from_session(app_key.clone(), "", url.to_string(), session),
encrypt_type: ENCRYPT_TYPE_AES.to_string(),
charset: constants::CHARSET_UTF8.to_string(),
sign_type: SIGN_TYPE_RSA2.to_string(),
format: FORMAT_JSON.to_string(),
encrypt_key: None,
private_key: None,
alipay_public_key: None,
app_cert: None,
alipay_public_cert: None,
alipay_root_cert: None,
use_cert: false,
cache_certs: Arc::new(DashMap::new())
}
}
pub fn get_app_cert_sn(&self) -> LabradorResult<String> {
let pem = self.app_cert.to_owned().unwrap_or_default();
#[cfg(not(feature = "openssl-crypto"))]
fn get_cert_sn(pem: &[u8]) -> LabradorResult<String> {
let (data, x509) = x509_parser::pem::parse_x509_pem(pem)?;
let cert = x509.parse_x509()?;
let issuer = iter2string(cert.issuer())?;
let serial_number = cert.serial.to_string();
let data = issuer + &serial_number;
let app_cert_sn = md5(data);
Ok(app_cert_sn)
}
#[cfg(feature = "openssl-crypto")]
fn get_cert_sn(pem: &[u8]) -> LabradorResult<String> {
let x509 = X509::from_pem(pem)?;
let issuer = iter2string(x509.issuer_name().entries())?;
let serial_number = x509.serial_number().to_bn()?.to_dec_str()?;
let data = issuer + &serial_number;
Ok(md5(data))
}
get_cert_sn(pem.as_bytes())
}
pub fn get_root_cert_sn(&self) -> LabradorResult<String> {
let pem = self.alipay_root_cert.to_owned().unwrap_or_default();
#[cfg(not(feature = "openssl-crypto"))]
fn get_cert_sn(pem: &[u8]) -> LabradorResult<String> {
let mut sns = Vec::new();
for pem in x509_parser::pem::Pem::iter_from_buffer(pem) {
match pem {
Ok(pem) => {
let cert = pem.parse_x509()?;
let algorithm = cert.signature_algorithm.oid().to_string();
if algorithm.starts_with("1.2.840.113549.1.1") {
continue;
}
let issuer = iter2string(cert.issuer())?;
let serial_number = cert.serial.to_string();
let data = issuer + &serial_number;
sns.push(md5(data));
}
Err(e) => {
tracing::error!("Error while decoding PEM entry {:?}", e);
}
}
}
Ok(sns.join("_"))
}
#[cfg(feature = "openssl-crypto")]
fn get_cert_sn(pem: &[u8]) -> LabradorResult<String> {
let x509s = X509::stack_from_pem(pem)?;
let alipay_root_cert_sn = x509s.iter().filter(|x509| {
let algorithm = x509.signature_algorithm().object().nid();
algorithm == Nid::SHA256WITHRSAENCRYPTION || algorithm == Nid::SHA1WITHRSAENCRYPTION
}).map(|x509| {
let issuer = iter2string(x509.issuer_name().entries())?;
let serial_number = x509.serial_number().to_bn()?.to_dec_str()?;
let data = issuer + &serial_number;
Ok( hex::encode(hash(MessageDigest::md5(), data.as_ref())?))
}).map(|cert: LabradorResult<String>| cert.unwrap_or_default()).collect::<Vec<String>>().join("_");
Ok(alipay_root_cert_sn)
}
get_cert_sn(pem.as_bytes())
}
pub fn init_alipay_public_cert(&self) -> LabradorResult<()> {
if !self.cache_certs.is_empty() {
return Ok(())
}
let pem = self.alipay_public_cert.to_owned().unwrap_or_default();
#[cfg(not(feature = "openssl-crypto"))]
fn get_cert_sn(pem: &[u8]) -> LabradorResult<Vec<(String, String)>> {
let mut resp = Vec::new();
for pem in x509_parser::pem::Pem::iter_from_buffer(pem) {
match pem {
Ok(pem) => {
let (_, cert) = parse_x509_certificate(&pem.contents)?;
let algorithm = cert.signature_algorithm.oid().to_string();
let public_key = cert.public_key();
let issuer = iter2string(cert.issuer())?;
let serial_number = cert.serial.to_string();
let data = issuer + &serial_number;
let sn = md5(data);
resp.push((sn, base64::encode(public_key.raw)));
}
Err(e) => {
tracing::error!("Error while decoding PEM entry {:?}", e);
}
}
}
Ok(resp)
}
#[cfg(feature = "openssl-crypto")]
fn get_cert_sn(pem: &[u8]) -> LabradorResult<Vec<(String, String)>> {
let x509s = X509::stack_from_pem(pem)?;
let mut resp = Vec::new();
for x509 in x509s.iter() {
let issuer = iter2string(x509.issuer_name().entries())?;
let serial_number = x509.serial_number().to_bn()?.to_dec_str()?;
let data = issuer + &serial_number;
let sn = md5(data);
let pk = x509.public_key()?;
let rpk = pk.public_key_to_pem()?;
resp.push((sn, base64::encode(&rpk)));
}
Ok(resp)
}
for (sn, cert) in get_cert_sn(pem.as_bytes())? {
self.cache_certs.insert(sn, cert);
}
Ok(())
}
pub fn get_alipay_public_key(&self) -> LabradorResult<String> {
let pem = self.alipay_public_cert.to_owned().unwrap_or_default();
#[cfg(not(feature = "openssl-crypto"))]
fn get_cert(pem: &[u8]) -> LabradorResult<(String, String)> {
let (r, pem) = x509_parser::pem::parse_x509_pem(pem)?;
let (_, cert) = parse_x509_certificate(&pem.contents)?;
let public_key = cert.public_key();
let issuer = iter2string(cert.issuer())?;
let serial_number = cert.serial.to_string();
let data = issuer + &serial_number;
let sn = md5(data);
Ok((sn, base64::encode(public_key.raw)))
}
#[cfg(feature = "openssl-crypto")]
fn get_cert(pem: &[u8]) -> LabradorResult<(String, String)> {
let x509 = X509::from_pem(pem)?;
let pk = x509.public_key()?;
let issuer = iter2string(x509.issuer_name().entries())?;
let serial_number = x509.serial_number().to_bn()?.to_dec_str()?;
let data = issuer + &serial_number;
let sn = md5(data);
Ok((sn, base64::encode(pk.public_key_to_pem()?)))
}
let (sn, pk) = get_cert(pem.as_bytes())?;
if let Some(key) = self.cache_certs.get(&sn) {
let v = key.value();
Ok(v.to_string())
} else {
self.cache_certs.insert(sn, pk.to_string());
Ok(pk.to_string())
}
}
pub fn set_private_key_path(mut self, private_key: &str) -> LabradorResult<Self> {
if private_key.is_empty() {
return Err(LabraError::InvalidSignature("私钥文件有误!".to_string()));
}
let content = fs::read_to_string(private_key)?;
self.private_key = content.into();
Ok(self)
}
pub fn set_private_key(mut self, private_key: &str) -> LabradorResult<Self> {
if private_key.is_empty() {
return Err(LabraError::InvalidSignature("私钥内容有误!".to_string()));
}
self.private_key = private_key.to_string().into();
Ok(self)
}
pub fn set_encrypt_type(mut self, encrypt_type: &str) -> Self {
self.encrypt_type = encrypt_type.to_string().into();
self
}
pub fn set_format(mut self, format: &str) -> Self {
self.format = format.to_string().into();
self
}
pub fn use_cert(mut self, use_cert: bool) -> Self {
self.use_cert = use_cert;
self
}
pub fn set_encrypt_key(mut self, encrypt_key: &str) -> Self {
self.encrypt_key = encrypt_key.to_string().into();
self
}
pub fn set_alipay_public_key(mut self, alipay_public_key: &str) -> Self {
self.alipay_public_key = alipay_public_key.to_string().into();
self
}
pub fn set_sign_type(mut self, sign_type: &str) -> Self {
self.sign_type = sign_type.to_string().into();
self
}
pub fn set_charset(mut self, charset: &str) -> Self {
self.charset = charset.to_string().into();
self
}
pub fn set_app_cert_path(mut self, cert_path: &str) -> LabradorResult<Self> {
if cert_path.is_empty() {
return Err(LabraError::InvalidSignature("证书文件有误!".to_string()));
}
let content = fs::read_to_string(cert_path)?;
self.app_cert = content.into();
Ok(self)
}
pub fn set_app_cert(mut self, cert: &str) -> Self {
self.app_cert = cert.to_string().into();
self
}
pub fn set_alipay_public_cert_path(mut self, cert_path: &str) -> LabradorResult<Self> {
if cert_path.is_empty() {
return Err(LabraError::InvalidSignature("证书文件有误!".to_string()));
}
let content = fs::read_to_string(cert_path)?;
self.alipay_public_cert = content.into();
Ok(self)
}
pub fn set_alipay_public_cert(mut self, cert: &str) -> Self {
self.alipay_public_cert = cert.to_string().into();
self
}
pub fn set_alipay_root_cert_path(mut self, cert_path: &str) -> LabradorResult<Self> {
if cert_path.is_empty() {
return Err(LabraError::InvalidSignature("证书文件有误!".to_string()));
}
let content = fs::read_to_string(cert_path)?;
self.alipay_root_cert = content.into();
Ok(self)
}
pub fn set_alipay_root_cert(mut self, cert: &str) -> Self {
self.alipay_root_cert = cert.to_string().into();
self
}
fn sign(&self, params: &str) -> LabradorResult<String> {
let private_key = self.private_key.to_owned().unwrap_or_default();
let content = base64::decode(&private_key)?;
let sign = PrpCrypto::rsa_sha256_sign(params, &private_key)?;
Ok(sign)
}
fn verify(&self, source: &str, signature: &str, cert: Option<&String>) -> LabradorResult<bool> {
let mut public_key = cert.map(|v| v.to_string()).unwrap_or_default();
if public_key.is_empty() {
if self.alipay_public_cert.is_some() && self.use_cert {
public_key = self.get_alipay_public_key()?;
} else {
public_key = self.alipay_public_key.to_owned().unwrap_or_default();
}
}
let _ = PrpCrypto::rsa_sha256_verify(&public_key, source, signature)?;
Ok(true)
}
fn get_redirect_url<>(&self, holder: &RequestParametersHolder) -> LabradorResult<String> {
let url_sb = self.api_client.api_path.to_owned();
let params = holder.get_sorted_map();
let param = serde_urlencoded::to_string(params)?;
Ok(format!("{}?{}", url_sb, param))
}
fn get_request_url(&self, holder: &RequestParametersHolder) -> LabradorResult<String> {
let mut url_sb = self.api_client.api_path.to_owned();
let sys_must = &holder.protocal_must_params;
let sys_must_query = serde_urlencoded::to_string(sys_must)?;
let opt_param = &holder.protocal_opt_params;
let sys_opt_query = serde_urlencoded::to_string(opt_param)?;
url_sb += "?";
url_sb += &sys_must_query;
if !sys_opt_query.is_empty() {
url_sb += "&";
url_sb += &sys_opt_query;
}
Ok(url_sb)
}
fn get_sdk_params(&self, holder: &RequestParametersHolder) -> LabradorResult<String> {
let mut url_sb = String::default();
let sorted_params = holder.get_sorted_map();
let sort_sql = serde_urlencoded::to_string(sorted_params)?;
url_sb.push_str(&sort_sql);
Ok(url_sb)
}
fn get_request_holder_with_sign<D, M>(&self, request: D, access_token: Option<String>, app_auth_token: Option<String>, target_app_id: Option<String>) -> LabradorResult<RequestParametersHolder> where D: AlipayRequest<M>, M: Serialize {
let mut holder = RequestParametersHolder::new();
let mut app_params = request.get_text_params();
let empty_str = &"".to_string();
let biz_content = app_params.get(constants::BIZ_CONTENT_KEY).unwrap_or_else(|| empty_str);
let biz_model = request.get_biz_model();
if biz_content.is_empty() && biz_model.is_some() {
let biz_model = biz_model.unwrap();
app_params.insert(constants::BIZ_CONTENT_KEY.to_string(), serde_json::to_string(&biz_model)?);
}
if request.is_need_encrypt() {
let biz_content = app_params.get(constants::BIZ_CONTENT_KEY).unwrap_or_else(|| empty_str);
if biz_content.is_empty() {
return Err(LabraError::ApiError("当前API不支持加密请求".to_string()))
}
if self.encrypt_type.is_empty() || self.encrypt_key.is_none() {
return Err(LabraError::ApiError("API请求要求加密,则必须设置密钥类型[encryptType]和加密密钥[encryptKey]".to_string()))
}
let key = self.encrypt_key.to_owned().unwrap_or_default();
let prp = PrpCrypto::new(key.into_bytes());
let encrypt_content = prp.aes_128_cbc_encrypt_data(biz_content, Some(&get_nonce_str()))?;
let encrypt_content = String::from_utf8_lossy(&encrypt_content).to_string();
app_params.insert(constants::BIZ_CONTENT_KEY.to_string(), encrypt_content);
}
if let Some(app_auth_token) = app_auth_token {
app_params.insert(constants::APP_AUTH_TOKEN.to_string(), app_auth_token);
}
holder.set_application_params(app_params);
let mut protocal_must_params = BTreeMap::new();
protocal_must_params.insert(constants::METHOD.to_string(), request.get_api_method_name().get_method());
protocal_must_params.insert(constants::VERSION.to_string(), request.get_api_version());
protocal_must_params.insert(constants::APP_ID.to_string(), self.api_client.app_key.to_owned());
protocal_must_params.insert(constants::SIGN_TYPE.to_string(), self.sign_type.to_string());
if !request.get_terminal_type().is_empty() {
protocal_must_params.insert(constants::TERMINAL_TYPE.to_string(), request.get_terminal_type());
}
if !request.get_terminal_info().is_empty() {
protocal_must_params.insert(constants::TERMINAL_INFO.to_string(), request.get_terminal_info());
}
if !request.get_notify_url().is_empty() {
protocal_must_params.insert(constants::NOTIFY_URL.to_string(), request.get_notify_url());
}
if !request.get_return_url().is_empty() {
protocal_must_params.insert(constants::RETURN_URL.to_string(), request.get_return_url());
}
protocal_must_params.insert(constants::CHARSET.to_string(), self.charset.to_string());
if let Some(target_app_id) = target_app_id {
protocal_must_params.insert(constants::TARGET_APP_ID.to_string(), target_app_id);
}
if request.is_need_encrypt() {
protocal_must_params.insert(constants::ENCRYPT_TYPE.to_string(), self.encrypt_type.to_string());
}
if let Some(_) = &self.app_cert {
let app_cert_sn = self.get_app_cert_sn()?;
if !app_cert_sn.is_empty() {
protocal_must_params.insert(constants::APP_CERT_SN.to_string(), app_cert_sn);
}
}
if let Some(_) = &self.alipay_root_cert {
let root_cert_sn = self.get_root_cert_sn()?;
if !root_cert_sn.is_empty() {
protocal_must_params.insert(constants::ALIPAY_ROOT_CERT_SN.to_string(), root_cert_sn);
}
}
protocal_must_params.insert(constants::TIMESTAMP.to_string(), Local::now().naive_local().format(constants::FORMAT_TIME).to_string());
holder.set_protocal_must_params(protocal_must_params.to_owned());
let mut protocal_opt_params = BTreeMap::new();
protocal_opt_params.insert(constants::FORMAT.to_string(), self.format.to_string());
if let Some(access_token) = access_token {
protocal_opt_params.insert(constants::ACCESS_TOKEN.to_string(), access_token);
}
if !request.get_prod_code().is_empty() {
protocal_opt_params.insert(constants::PROD_CODE.to_string(), request.get_prod_code());
}
holder.set_protocal_opt_params(protocal_opt_params);
if !self.sign_type.is_empty() {
let sign_content = holder.get_signature_content();
protocal_must_params.insert(constants::SIGN.to_string(), self.sign_with_type(&sign_content)?);
} else {
protocal_must_params.insert(constants::SIGN.to_string(), "".to_string());
}
holder.set_protocal_must_params(protocal_must_params);
Ok(holder)
}
fn sign_with_type(&self, sign_content: &str) -> LabradorResult<String> {
match self.sign_type.as_str() {
constants::SIGN_TYPE_RSA2 => {
let private_key = self.private_key.to_owned().unwrap_or_default();
let sign = PrpCrypto::rsa_sha256_sign(sign_content, &private_key)?;
Ok(sign)
}
_ => return Err(LabraError::InvalidSignature("不支持的加密方式".to_string()))
}
}
pub async fn auto_load_cert(&self, alipay_cert_sn: &str) -> LabradorResult<String> {
if self.cache_certs.is_empty() && self.use_cert {
self.init_alipay_public_cert();
}
if let Some(cert) = self.cache_certs.get(alipay_cert_sn) {
let data = cert.value();
tracing::info!("获取内存中平台证书:{}", data);
Ok(data.to_string())
} else {
let mut req = AlipayOpenAppAlipaycertDownloadRequest::new();
let model = AlipayOpenAppAlipaycertDownloadModel { alipay_cert_sn: alipay_cert_sn.to_string() };
req.biz_model = model.into();
let method = req.get_api_method_name();
let holder = self.get_request_holder_with_sign(req, None, None, None)?;
let url = self.get_request_url(&holder)?;
let req = LabraRequest::new().url(url).method(Method::Get).form(&holder.application_params).req_type(RequestType::Form);
let result = self.api_client.request(req).await?.text()?;
match AlipayBaseResponse::parse(&result, method) {
Ok(mut resp) => {
let response = resp.get_biz_model::<AlipayOpenAppAlipaycertDownloadResponse>()?;
let content = response.alipay_cert_content;
tracing::info!("获取下载平台证书:{}", content);
self.cache_certs.insert(alipay_cert_sn.to_string(), content.to_string());
Ok(content)
}
Err(err) => Err(err)
}
}
}
fn page_excute<D, M>(&self, mut http_method: &str, request: D)
-> LabradorResult<AlipayBaseResponse> where D: AlipayRequest<M>, M: Serialize {
if http_method.is_empty() {
http_method = "POST";
}
let mut resp = AlipayBaseResponse::new();
let holder = self.get_request_holder_with_sign(request, None, None, None)?;
if http_method.to_uppercase().eq("GET") {
let body = self.get_redirect_url(&holder)?;
resp.set_body(body);
} else {
let url = self.get_request_url(&holder)?;
let body = self.build_form(&url, &holder.application_params);
resp.set_body(body);
}
Ok(resp)
}
fn sdk_excute<D, M>(&self, request: D)
-> LabradorResult<AlipayBaseResponse> where D: AlipayRequest<M>, M: Serialize {
let mut resp = AlipayBaseResponse::new();
let holder = self.get_request_holder_with_sign(request, None, None, None)?;
let body = self.get_sdk_params(&holder)?;
resp.set_body(body);
Ok(resp)
}
async fn excute<D, M>(&self, request: D, access_token: Option<String>, app_auth_token: Option<String>, target_app_id: Option<String>) -> LabradorResult<AlipayBaseResponse>
where D: AlipayRequest<M>, M: Serialize {
if self.alipay_root_cert.is_some() || self.use_cert {
return self.cert_excute(request, access_token, app_auth_token, target_app_id).await
}
let method = request.get_api_method_name();
let holder = self.get_request_holder_with_sign(request, access_token, app_auth_token, target_app_id)?;
let url = self.get_request_url(&holder)?;
let req = LabraRequest::new().url(url).method(Method::Post).form(&holder.application_params).req_type(RequestType::Form);
let result = self.api_client.request(req).await?.text()?;
match AlipayBaseResponse::parse(&result, method) {
Ok(mut resp) => {
let sign = resp.get_sign();
if !sign.is_empty() || resp.is_success() {
let body = resp.body.to_owned().unwrap_or_default();
let result = self.verify(&body, &sign, None)?;
if !result {
return Err(LabraError::InvalidSignature("sign check fail: check Sign and Data Fail!".to_string()))
}
}
Ok(resp)
}
Err(err) => Err(err)
}
}
async fn cert_excute<D, M>(&self, request: D, access_token: Option<String>, app_auth_token: Option<String>, target_app_id: Option<String>) -> LabradorResult<AlipayBaseResponse>
where D: AlipayRequest<M>, M: Serialize {
let method = request.get_api_method_name();
let holder = self.get_request_holder_with_sign(request, access_token, app_auth_token, target_app_id)?;
let url = self.get_request_url(&holder)?;
let req = LabraRequest::new().url(url).method(Method::Post).form(&holder.application_params).req_type(RequestType::Form);
let result = self.api_client.request(req).await?.text()?;
match AlipayBaseResponse::parse(&result, method) {
Ok(mut resp) => {
let sign = resp.get_sign();
if !sign.is_empty() || resp.is_success() {
let body = resp.body.to_owned().unwrap_or_default();
let alipay_cert_sn = resp.get_alipay_cert_sn();
if !alipay_cert_sn.is_empty() {
let cert: Option<String> = Some(self.auto_load_cert(&alipay_cert_sn).await.unwrap_or_default());
let result = self.verify(&body, &sign, cert.as_ref())?;
if !result {
return Err(LabraError::InvalidSignature("sign check fail: check Sign and Data Fail!".to_string()))
}
}
}
Ok(resp)
}
Err(err) => Err(err)
}
}
fn build_form(&self, url: &str, parameters: &BTreeMap<String, String>) -> String {
let mut form = String::from("<form name=\"punchout_form\" method=\"post\" action=\"");
form.push_str(url);
form.push_str("\">\n");
form.push_str(&self.build_hidden_fields(parameters));
form.push_str("<input type=\"submit\" value=\"立即支付\" style=\"display:none\" >\n");
form.push_str("</form>\n");
form.push_str("<script>document.forms[0].submit();</script>");
form
}
fn build_hidden_fields(&self, parameters: &BTreeMap<String, String>) -> String {
if parameters.is_empty() || parameters.len() == 0 {
return "".to_string();
}
let mut param = String::default();
for (k, v) in parameters.into_iter() {
if k.is_empty() || v.is_empty() {
continue;
}
param.push_str(&self.build_hidden_field(k, v));
}
param
}
fn build_hidden_field(&self, k: &str, v: &str) -> String {
let mut param = String::from("<input type=\"hidden\" name=\"");
param.push_str(k);
param.push_str("\" value=\"");
let a = v.replace("\"", """);
param.push_str(&a);
param.push_str("\">\n");
param.to_string()
}
pub fn wap_pay(&self, http_method: Option<&str>, req: AlipayTradeWapPayRequest<AlipayTradeWapPayModel>) -> LabradorResult<AlipayBaseResponse> {
self.page_excute(http_method.unwrap_or("POST"), req)
}
pub fn pc_pay(&self, http_method: Option<&str>, req: AlipayTradePagePayRequest<AlipayTradePagePayModel>) -> LabradorResult<AlipayBaseResponse> {
self.page_excute(http_method.unwrap_or("POST"), req)
}
pub fn app_pay(&self, req: AlipayTradeAppPayRequest<AlipayTradeAppPayModel>) -> LabradorResult<AlipayBaseResponse> {
self.sdk_excute(req)
}
pub async fn unified_order_pay(&self, req: AlipayTradePayRequest<AlipayTradePayModel>) -> LabradorResult<AlipayUnifiedOrderPayResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayUnifiedOrderPayResponse>()
}
pub async fn face_pay(&self, req: AlipayTradePayRequest<AlipayFaceOrderPayModel>) -> LabradorResult<AlipayFaceOrderPayResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayFaceOrderPayResponse>()
}
pub async fn cycle_pay(&self, req: AlipayTradePayRequest<AlipayCycleOrderPayModel>) -> LabradorResult<AlipayCycleOrderPayResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayCycleOrderPayResponse>()
}
pub async fn pre_auth_online_pay(&self, req: AlipayTradePayRequest<AlipayPreAuthOnlinePayModel>) -> LabradorResult<AlipayPreAuthOnlinePayResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayPreAuthOnlinePayResponse>()
}
pub async fn create_pre_order(&self, req: AlipayTradePrecreateRequest<AlipayTradePrecreateModel>) -> LabradorResult<AlipayPreOrderResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayPreOrderResponse>()
}
pub async fn create_unified_order(&self, req: AlipayTradeCreateRequest<AlipayTradeCreateModel>) -> LabradorResult<AlipayCreateUnifiedOrderResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayCreateUnifiedOrderResponse>()
}
pub async fn query_order(&self, req: AlipayTradeQueryRequest<AlipayTradeQueryModel>) -> LabradorResult<AlipayQueryOrderResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayQueryOrderResponse>()
}
pub async fn close_order(&self, req: AlipayTradeCloseRequest<AlipayTradeCloseModel>) -> LabradorResult<AlipayCloseOrderResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayCloseOrderResponse>()
}
pub async fn refund_order(&self, req: AlipayTradeRefundRequest<AlipayTradeRefundModel>) -> LabradorResult<AlipayRefundOrderResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayRefundOrderResponse>()
}
pub async fn query_refund_order(&self, req: AlipayTradeFastpayRefundQueryRequest<AlipayTradeFastpayRefundQueryModel>) -> LabradorResult<AlipayRefundQueryResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayRefundQueryResponse>()
}
pub async fn cancel_order(&self, req: AlipayTradeCancelRequest<AlipayTradeCancelModel>) -> LabradorResult<AlipayCancelOrderResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayCancelOrderResponse>()
}
pub fn parse_order_notify(&self, notify_data: &str) -> LabradorResult<AlipayNotifyResponse> {
let mut data = serde_urlencoded::from_str::<BTreeMap<String, String>>(notify_data)?;
let sign_type = data.get(constants::SIGN).map(|v| v.to_owned()).unwrap_or_default();
let sign = data.get(constants::SIGN).map(|v| urlencoding::decode(v).unwrap_or_default().into_owned()).unwrap_or_default();
let source = data.into_iter().filter(|(k,v)| !k.is_empty() && !v.is_empty() && k.ne(constants::SIGN) && k.ne(constants::SIGN_TYPE)).map(|(k, v)| format!("{}={}", k, urlencoding::decode(&v).unwrap_or_default().replace("+", " "))).collect::<Vec<String>>().join("&");
let result = self.verify(&source, &sign, None)?;
if !result {
return Err(LabraError::InvalidSignature("回调结果验签失败!".to_string()))
}
let notify_data = format!("{}&{}={}&{}={}", source, constants::SIGN, sign, constants::SIGN_TYPE, sign_type);
let notify = serde_urlencoded::from_str::<AlipayNotifyResponse>(¬ify_data)?;
Ok(notify)
}
pub async fn system_oauth_token(&self, req: AlipaySystemOauthTokenRequest) -> LabradorResult<AlipaySystemOauthTokenResponse> {
let resp = self.excute::<_, String>(req, None, None, None).await?;
resp.get_biz_model::<AlipaySystemOauthTokenResponse>()
}
pub async fn open_auth_token_app(&self, req: AlipayOpenAuthTokenAppRequest<AlipayOpenAuthTokenAppModel>) -> LabradorResult<AlipayOpenAuthTokenAppResponse> {
let resp = self.excute(req, None, None, None).await?;
resp.get_biz_model::<AlipayOpenAuthTokenAppResponse>()
}
}
#[cfg(feature = "openssl-crypto")]
fn iter2string(iter: X509NameEntries) -> LabradorResult<String> {
let mut string: String = String::from("");
for value in iter {
let data = value.data().as_utf8()?.to_string();
let key = value.object().nid().short_name()?.to_owned();
string.insert_str(0, &(key + "=" + &data + ","));
}
string.pop();
Ok(string)
}
#[cfg(not(feature = "openssl-crypto"))]
fn iter2string(iter: &X509Name) -> LabradorResult<String> {
let mut string: String = String::from("");
for v in iter.to_string().split(",") {
string.insert_str(0, &(v.trim().to_string() + ","));
}
string.pop();
Ok(string)
}