diff --git a/src/PaySharp.Unionpay/Util.cs b/src/PaySharp.Unionpay/CertUtil.cs
similarity index 65%
rename from src/PaySharp.Unionpay/Util.cs
rename to src/PaySharp.Unionpay/CertUtil.cs
index 01170b3..c449330 100644
--- a/src/PaySharp.Unionpay/Util.cs
+++ b/src/PaySharp.Unionpay/CertUtil.cs
@@ -16,20 +16,16 @@ using PaySharp.Unionpay.Properties;
namespace PaySharp.Unionpay
{
- internal static class Util
+ public static class CertUtil
{
#region 字段
private static Pkcs12Store _pkcs12Store;
private static string _aliase;
-
- #endregion
-
- #region 证书
-
- private static X509Certificate ACPENCCER = null;
- private static X509Certificate ACPROOTCER = null;
- private static X509Certificate ACPMIDDLECER = null;
+ private static X509Certificate _acpEncCer;
+ private static X509Certificate _acpRootCer;
+ private static X509Certificate _acpMiddleCer;
+ internal static bool IsTest { get; set; }
#endregion
@@ -38,13 +34,23 @@ namespace PaySharp.Unionpay
///
/// 获取Pkcs12Store
///
- /// 证书路径
+ /// 证书路径或base64字符串
/// 证书密码
///
- private static void GetPkcs12Store(string path, string pwd)
+ private static void GetPkcs12Store(string cert, string pwd)
{
- using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
- var pkcs12Store = new Pkcs12Store(fileStream, pwd.ToCharArray());
+ Stream stream;
+ if (File.Exists(cert))
+ {
+ stream = new FileStream(cert, FileMode.Open, FileAccess.Read, FileShare.Read);
+ }
+ else
+ {
+ var buffer = Convert.FromBase64String(cert);
+ stream = new MemoryStream(buffer);
+ }
+
+ var pkcs12Store = new Pkcs12Store(stream, pwd.ToCharArray());
foreach (string item in pkcs12Store.Aliases)
{
if (pkcs12Store.IsKeyEntry(item))
@@ -53,19 +59,21 @@ namespace PaySharp.Unionpay
_aliase = item;
}
}
+
+ stream.Dispose();
}
///
/// 获取证书编号
///
- /// 证书路径
+ /// 证书路径或base64字符串
/// 证书密码
///
- public static string GetCertId(string path, string pwd)
+ public static string GetCertId(string cert, string pwd)
{
if (string.IsNullOrEmpty(_aliase))
{
- GetPkcs12Store(path, pwd);
+ GetPkcs12Store(cert, pwd);
}
return _pkcs12Store
@@ -84,14 +92,14 @@ namespace PaySharp.Unionpay
///
/// 获取证书编号
///
- /// 证书路径
+ /// 证书路径或base64字符串
/// 证书密码
///
- public static AsymmetricKeyParameter GetCertKey(string path, string pwd)
+ public static AsymmetricKeyParameter GetCertKey(string cert, string pwd)
{
if (string.IsNullOrEmpty(_aliase))
{
- GetPkcs12Store(path, pwd);
+ GetPkcs12Store(cert, pwd);
}
return _pkcs12Store
@@ -136,7 +144,7 @@ namespace PaySharp.Unionpay
var signByte = Convert.FromBase64String(sign);
var x509Cert = VerifyAndGetPubKey(signPubKeyCert);
- return x509Cert == null ? false : VerifySignature(x509Cert.GetPublicKey(), signByte, dataByte);
+ return x509Cert != null && VerifySignature(x509Cert.GetPublicKey(), signByte, dataByte);
}
private static bool VerifySignature(AsymmetricKeyParameter key, byte[] base64DecodingSignStr, byte[] srcByte)
@@ -156,15 +164,8 @@ namespace PaySharp.Unionpay
private static bool VerifyCertificate(X509Certificate x509Cert)
{
var cn = GetIdentitiesFromCertficate(x509Cert);
- try
- {
- x509Cert.CheckValidity();//验证有效期
- if (!VerifyCertificateChain(x509Cert))//验证书链
- {
- return false;
- }
- }
- catch
+ x509Cert.CheckValidity();//验证有效期
+ if (!VerifyCertificateChain(x509Cert))//验证书链
{
return false;
}
@@ -192,117 +193,70 @@ namespace PaySharp.Unionpay
return false;
}
- try
+ var selector = new X509CertStoreSelector
{
- var selector = new X509CertStoreSelector
- {
- Subject = cert.SubjectDN
- };
+ Subject = cert.SubjectDN
+ };
- ISet trustAnchors = new HashSet
- {
- new TrustAnchor(rootCert, null)
- };
- var pkixParams = new PkixBuilderParameters(trustAnchors, selector);
-
- IList intermediateCerts = new ArrayList
- {
- rootCert,
- middleCert,
- cert
- };
-
- pkixParams.IsRevocationEnabled = false;
-
- var intermediateCertStore = X509StoreFactory.Create(
- "Certificate/Collection",
- new X509CollectionStoreParameters(intermediateCerts));
- pkixParams.AddStore(intermediateCertStore);
-
- var pathBuilder = new PkixCertPathBuilder();
- var result = pathBuilder.Build(pkixParams);
- var path = result.CertPath;
- return true;
- }
- catch
+ ISet trustAnchors = new HashSet
{
- return false;
- }
+ new TrustAnchor(rootCert, null)
+ };
+ var pkixParams = new PkixBuilderParameters(trustAnchors, selector);
+
+ IList intermediateCerts = new ArrayList
+ {
+ rootCert,
+ middleCert,
+ cert
+ };
+
+ pkixParams.IsRevocationEnabled = false;
+
+ var intermediateCertStore = X509StoreFactory.Create(
+ "Certificate/Collection",
+ new X509CollectionStoreParameters(intermediateCerts));
+ pkixParams.AddStore(intermediateCertStore);
+
+ var pathBuilder = new PkixCertPathBuilder();
+ var result = pathBuilder.Build(pkixParams);
+ _ = result.CertPath;
+ return true;
}
private static X509Certificate GetCert(byte[] input)
{
- try
- {
- return new X509CertificateParser().ReadCertificate(input);
- }
- catch
- {
- return null;
- }
+ return new X509CertificateParser().ReadCertificate(input);
}
private static X509Certificate GetRootCert()
{
- try
+ if (_acpRootCer is null)
{
- if (ACPROOTCER is null)
- {
-#if DEBUG
- ACPROOTCER = GetCert(Resources.acp_test_root);
-#else
- ACPROOTCER= GetCert(Resources.acp_prod_root);
-#endif
- }
+ _acpRootCer = IsTest ? GetCert(Resources.acp_test_root) : GetCert(Resources.acp_prod_root);
+ }
- return ACPROOTCER;
- }
- catch
- {
- return null;
- }
+ return _acpRootCer;
}
private static X509Certificate GetMiddleCert()
{
- try
+ if (_acpMiddleCer is null)
{
- if (ACPMIDDLECER is null)
- {
-#if DEBUG
- ACPMIDDLECER = GetCert(Resources.acp_test_middle);
-#else
- ACPMIDDLECER= GetCert(Resources.acp_prod_middle);
-#endif
- }
+ _acpMiddleCer = IsTest ? GetCert(Resources.acp_test_middle) : GetCert(Resources.acp_prod_middle);
+ }
- return ACPMIDDLECER;
- }
- catch
- {
- return null;
- }
+ return _acpMiddleCer;
}
private static X509Certificate GetEncCert()
{
- try
+ if (_acpEncCer is null)
{
- if (ACPENCCER is null)
- {
-#if DEBUG
- ACPENCCER = GetCert(Resources.acp_test_enc);
-#else
- ACPENCCER= GetCert(Resources.acp_prod_enc);
-#endif
- }
+ _acpEncCer = IsTest ? GetCert(Resources.acp_test_enc) : GetCert(Resources.acp_prod_enc);
+ }
- return ACPENCCER;
- }
- catch
- {
- return null;
- }
+ return _acpEncCer;
}
private static string GetIdentitiesFromCertficate(X509Certificate aCert)
@@ -322,20 +276,13 @@ namespace PaySharp.Unionpay
private static X509Certificate GetPubKeyCert(string pubKeyCert)
{
- try
- {
- pubKeyCert = pubKeyCert
- .Replace("-----END CERTIFICATE-----", "")
- .Replace("-----BEGIN CERTIFICATE-----", "");
- var x509CertBytes = Convert.FromBase64String(pubKeyCert);
- var cf = new X509CertificateParser();
- var x509Cert = cf.ReadCertificate(x509CertBytes);
- return x509Cert;
- }
- catch
- {
- return null;
- }
+ pubKeyCert = pubKeyCert
+ .Replace("-----END CERTIFICATE-----", "")
+ .Replace("-----BEGIN CERTIFICATE-----", "");
+ var x509CertBytes = Convert.FromBase64String(pubKeyCert);
+ var cf = new X509CertificateParser();
+ var x509Cert = cf.ReadCertificate(x509CertBytes);
+ return x509Cert;
}
#endregion
diff --git a/src/PaySharp.Unionpay/Domain/AppPayModel.cs b/src/PaySharp.Unionpay/Domain/AppPayModel.cs
index bbdedc8..6ba225c 100644
--- a/src/PaySharp.Unionpay/Domain/AppPayModel.cs
+++ b/src/PaySharp.Unionpay/Domain/AppPayModel.cs
@@ -16,5 +16,22 @@ namespace PaySharp.Unionpay.Domain
/// 支付卡类型
///
public string PayCardType { get; set; }
+
+ ///
+ /// 签约协议号
+ ///
+ public string ContractId
+ {
+ get => _contractId;
+ set
+ {
+ _contractId = value;
+ if (!string.IsNullOrEmpty(_contractId))
+ {
+ TxnSubType = "10";
+ }
+ }
+ }
+ private string _contractId;
}
}
diff --git a/src/PaySharp.Unionpay/Domain/BaseModel.cs b/src/PaySharp.Unionpay/Domain/BaseModel.cs
index 446810c..7b3df9d 100644
--- a/src/PaySharp.Unionpay/Domain/BaseModel.cs
+++ b/src/PaySharp.Unionpay/Domain/BaseModel.cs
@@ -59,6 +59,7 @@ namespace PaySharp.Unionpay.Domain
/// 交易子类
/// 01:自助消费,通过地址的方式区分前台消费和后台消费(含无跳转支付)
/// 03:分期付款
+ /// 10:签约支付(协议号支付)
///
[Required(ErrorMessage = "请设置交易子类")]
public string TxnSubType { get; internal set; } = "01";
diff --git a/src/PaySharp.Unionpay/Merchant.cs b/src/PaySharp.Unionpay/Merchant.cs
index 8a527f5..6be071d 100644
--- a/src/PaySharp.Unionpay/Merchant.cs
+++ b/src/PaySharp.Unionpay/Merchant.cs
@@ -60,10 +60,10 @@ namespace PaySharp.Unionpay
public string ReturnUrl { get; set; }
///
- /// 签名证书路径
+ /// 签名证书路径/base64字符串
///
[Ignore]
- [Required(ErrorMessage = "请设置签名证书路径")]
+ [Required(ErrorMessage = "请设置签名证书路径或base64字符串")]
public string CertPath { get; set; }
///
diff --git a/src/PaySharp.Unionpay/Request/BillDownloadRequest.cs b/src/PaySharp.Unionpay/Request/BillDownloadRequest.cs
index 5d7ba16..c66f87a 100644
--- a/src/PaySharp.Unionpay/Request/BillDownloadRequest.cs
+++ b/src/PaySharp.Unionpay/Request/BillDownloadRequest.cs
@@ -7,11 +7,7 @@ namespace PaySharp.Unionpay.Request
{
public BillDownloadRequest()
{
-#if DEBUG
- RequestUrl = "https://filedownload.test.95516.com/";
-#else
RequestUrl = "https://filedownload.95516.com/";
-#endif
}
internal override void Execute(Merchant merchant)
@@ -20,4 +16,4 @@ namespace PaySharp.Unionpay.Request
GatewayData.Remove("frontUrl");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/PaySharp.Unionpay/Response/BillDownloadResponse.cs b/src/PaySharp.Unionpay/Response/BillDownloadResponse.cs
index dd15b00..e110452 100644
--- a/src/PaySharp.Unionpay/Response/BillDownloadResponse.cs
+++ b/src/PaySharp.Unionpay/Response/BillDownloadResponse.cs
@@ -40,7 +40,7 @@ namespace PaySharp.Unionpay.Response
{
if (!string.IsNullOrEmpty(FileContent))
{
- _billFile = Util.Inflater(FileContent);
+ _billFile = CertUtil.Inflater(FileContent);
}
}
}
diff --git a/src/PaySharp.Unionpay/Response/NotifyResponse.cs b/src/PaySharp.Unionpay/Response/NotifyResponse.cs
index b159b51..072d75d 100644
--- a/src/PaySharp.Unionpay/Response/NotifyResponse.cs
+++ b/src/PaySharp.Unionpay/Response/NotifyResponse.cs
@@ -217,7 +217,7 @@ namespace PaySharp.Unionpay.Response
///
/// 清算金额
///
- [ReName(Name = "SettleAmt")]
+ [ReName(Name = "settleAmt")]
public string SettleAmount { get; set; }
///
diff --git a/src/PaySharp.Unionpay/SubmitProcess.cs b/src/PaySharp.Unionpay/SubmitProcess.cs
index 3bd304a..5ffca67 100644
--- a/src/PaySharp.Unionpay/SubmitProcess.cs
+++ b/src/PaySharp.Unionpay/SubmitProcess.cs
@@ -75,14 +75,14 @@ namespace PaySharp.Unionpay
{
gatewayData.Remove("signature");
- return Util.Sign(asymmetricKeyParameter, gatewayData.ToUrl(false));
+ return CertUtil.Sign(asymmetricKeyParameter, gatewayData.ToUrl(false));
}
internal static bool CheckSign(GatewayData gatewayData, string sign, string signPubKeyCert)
{
gatewayData.Remove("signature");
- return Util.VerifyData(gatewayData.ToUrl(false), sign, signPubKeyCert);
+ return CertUtil.VerifyData(gatewayData.ToUrl(false), sign, signPubKeyCert);
}
}
}
diff --git a/src/PaySharp.Unionpay/UnionpayGateway.cs b/src/PaySharp.Unionpay/UnionpayGateway.cs
index 2c708fa..dc3ce5e 100644
--- a/src/PaySharp.Unionpay/UnionpayGateway.cs
+++ b/src/PaySharp.Unionpay/UnionpayGateway.cs
@@ -33,8 +33,8 @@ namespace PaySharp.Unionpay
{
_merchant = merchant;
- _merchant.CertId = Util.GetCertId(merchant.CertPath, merchant.CertPwd);
- _merchant.CertKey = Util.GetCertKey(merchant.CertPath, merchant.CertPwd);
+ _merchant.CertId = CertUtil.GetCertId(merchant.CertPath, merchant.CertPwd);
+ _merchant.CertKey = CertUtil.GetCertKey(merchant.CertPath, merchant.CertPwd);
}
#if NETCOREAPP3_1
@@ -54,7 +54,16 @@ namespace PaySharp.Unionpay
#region 属性
- public override string GatewayUrl { get; set; } = "https://gateway.95516.com";
+ public override string GatewayUrl
+ {
+ get => _gatewayUrl;
+ set
+ {
+ _gatewayUrl = value;
+ CertUtil.IsTest = _gatewayUrl.Contains("test");
+ }
+ }
+ private string _gatewayUrl = "https://gateway.95516.com";
public new Merchant Merchant => _merchant;