mirror of
https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git
synced 2025-07-15 05:13:17 +08:00
fix(tenpayv3): 修复部分响应模型解密敏感数据字段时抛出异常的问题
This commit is contained in:
parent
9423dd5642
commit
ec6e3f7e7a
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class WechatTenpaySensitiveAttribute : Attribute
|
||||
{
|
||||
public WechatTenpaySensitiveAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -23,55 +23,59 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
|
||||
try
|
||||
{
|
||||
// 遍历并加密被标记为敏感数据的字段
|
||||
Utilities.ReflectionUtility.ReplacePropertyStringValue(ref request, (obj, prop, value) =>
|
||||
bool requireEncrypt = request.GetType().GetCustomAttributes<WechatTenpaySensitiveAttribute>(inherit: true).Any();
|
||||
if (requireEncrypt)
|
||||
{
|
||||
var attr = prop.GetCustomAttribute<WechatTenpaySensitivePropertyAttribute>();
|
||||
if (attr == null)
|
||||
return value;
|
||||
|
||||
if (Constants.EncryptionAlgorithms.RSA_2048_PKCS8_ECB.Equals(attr.Algorithm))
|
||||
// 遍历并加密被标记为敏感数据的字段
|
||||
Utilities.ReflectionUtility.ReplacePropertyStringValue(ref request, (obj, prop, value) =>
|
||||
{
|
||||
if (client.CertificateManager == null)
|
||||
throw new Exceptions.WechatTenpayRequestEncryptionException("Encrypt request failed, because there is no platform certificate in the manager.");
|
||||
var attr = prop.GetCustomAttribute<WechatTenpaySensitivePropertyAttribute>();
|
||||
if (attr == null)
|
||||
return value;
|
||||
|
||||
string certificate;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.WechatpayCertSerialNumber))
|
||||
if (Constants.EncryptionAlgorithms.RSA_2048_PKCS8_ECB.Equals(attr.Algorithm))
|
||||
{
|
||||
// 如果已在请求中指定特定的平台证书序列号,直接从管理器中取值
|
||||
var cert = client.CertificateManager.GetEntry(request.WechatpayCertSerialNumber!);
|
||||
if (!cert.HasValue)
|
||||
if (client.CertificateManager == null)
|
||||
throw new Exceptions.WechatTenpayRequestEncryptionException("Encrypt request failed, because there is no platform certificate in the manager.");
|
||||
|
||||
string certificate;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.WechatpayCertSerialNumber))
|
||||
{
|
||||
throw new Exceptions.WechatTenpayEventVerificationException("Encrypt request failed, because there is no platform certificate matched the serial number.");
|
||||
// 如果已在请求中指定特定的平台证书序列号,直接从管理器中取值
|
||||
var cert = client.CertificateManager.GetEntry(request.WechatpayCertSerialNumber!);
|
||||
if (!cert.HasValue)
|
||||
{
|
||||
throw new Exceptions.WechatTenpayEventVerificationException("Encrypt request failed, because there is no platform certificate matched the serial number.");
|
||||
}
|
||||
|
||||
certificate = cert.Value.Certificate;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果未在请求中指定特定的平台证书序列号,从管理器中取过期时间最远的
|
||||
var certs = client.CertificateManager.AllEntries().OrderByDescending(e => e.ExpireTime);
|
||||
if (!certs.Any())
|
||||
{
|
||||
throw new Exceptions.WechatTenpayEventVerificationException("Encrypt request failed, because there is no platform certificate in the manager.");
|
||||
}
|
||||
|
||||
var cert = certs.First();
|
||||
certificate = cert.Certificate;
|
||||
request.WechatpayCertSerialNumber = cert.SerialNumber;
|
||||
}
|
||||
|
||||
certificate = cert.Value.Certificate;
|
||||
return Utilities.RSAUtility.EncryptWithECBByCertificate(
|
||||
certificate: certificate,
|
||||
plainText: value
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果未在请求中指定特定的平台证书序列号,从管理器中取过期时间最远的
|
||||
var certs = client.CertificateManager.AllEntries().OrderByDescending(e => e.ExpireTime);
|
||||
if (!certs.Any())
|
||||
{
|
||||
throw new Exceptions.WechatTenpayEventVerificationException("Encrypt request failed, because there is no platform certificate in the manager.");
|
||||
}
|
||||
|
||||
var cert = certs.First();
|
||||
certificate = cert.Certificate;
|
||||
request.WechatpayCertSerialNumber = cert.SerialNumber;
|
||||
throw new Exceptions.WechatTenpayRequestEncryptionException("Unsupported encryption algorithm.");
|
||||
}
|
||||
|
||||
return Utilities.RSAUtility.EncryptWithECBByCertificate(
|
||||
certificate: certificate,
|
||||
plainText: value
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exceptions.WechatTenpayRequestEncryptionException("Unsupported encryption algorithm.");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (!(ex is Exceptions.WechatTenpayRequestEncryptionException))
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
@ -54,25 +55,29 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
return response;
|
||||
}
|
||||
|
||||
// 遍历并解密被标记为敏感数据的字段
|
||||
Utilities.ReflectionUtility.ReplacePropertyStringValue(ref response, (obj, prop, value) =>
|
||||
bool requireDecrypt = response.GetType().GetCustomAttributes<WechatTenpaySensitiveAttribute>(inherit: true).Any();
|
||||
if (requireDecrypt)
|
||||
{
|
||||
var attr = prop.GetCustomAttribute<WechatTenpaySensitivePropertyAttribute>();
|
||||
if (attr == null)
|
||||
return value;
|
||||
// 遍历并解密被标记为敏感数据的字段
|
||||
Utilities.ReflectionUtility.ReplacePropertyStringValue(ref response, (obj, prop, value) =>
|
||||
{
|
||||
var attr = prop.GetCustomAttribute<WechatTenpaySensitivePropertyAttribute>();
|
||||
if (attr == null)
|
||||
return value;
|
||||
|
||||
if (Constants.EncryptionAlgorithms.RSA_2048_PKCS8_ECB.Equals(attr.Algorithm))
|
||||
{
|
||||
return Utilities.RSAUtility.DecryptWithECB(
|
||||
privateKey: client.Credentials.MerchantCertPrivateKey,
|
||||
cipherText: value
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exceptions.WechatTenpayResponseDecryptionException("Unsupported decryption algorithm.");
|
||||
}
|
||||
});
|
||||
if (Constants.EncryptionAlgorithms.RSA_2048_PKCS8_ECB.Equals(attr.Algorithm))
|
||||
{
|
||||
return Utilities.RSAUtility.DecryptWithECB(
|
||||
privateKey: client.Credentials.MerchantCertPrivateKey,
|
||||
cipherText: value
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exceptions.WechatTenpayResponseDecryptionException("Unsupported decryption algorithm.");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (!(ex is Exceptions.WechatTenpayResponseDecryptionException))
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /applyment4sub/applyment/ 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class CreateApplyForSubMerchantApplymentRequest : WechatTenpayRequest
|
||||
{
|
||||
public static class Types
|
||||
|
@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /apply4sub/sub_merchants/{sub_mchid}/modify-settlement 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class ModifyApplyForSubMerchantSettlementRequest : WechatTenpayRequest
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -5,6 +5,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /apply4subject/applyment 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class CreateApplyForSubjectApplymentRequest : WechatTenpayRequest
|
||||
{
|
||||
public static class Types
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /bill/sub-merchant-fundflowbill 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class GetBillSubMerchantFundflowBillResponse : WechatTenpayResponse
|
||||
{
|
||||
public static class Types
|
||||
|
@ -5,6 +5,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /brand/profitsharing/orders 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class CreateBrandProfitSharingOrderRequest : WechatTenpayRequest
|
||||
{
|
||||
public static class Types
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /certificates 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class QueryCertificatesResponse : WechatTenpayResponse
|
||||
{
|
||||
public static class Types
|
||||
|
@ -5,6 +5,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /ecommerce/applyments 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class CreateEcommerceApplymentRequest : WechatTenpayRequest
|
||||
{
|
||||
public static class Types
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /ecommerce/applyments/out-request-no/{out_request_no} 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class GetEcommerceApplymentByOutRequestNumberResponse : WechatTenpayResponse
|
||||
{
|
||||
public static class Types
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /ecommerce/bill/fundflowbill 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class GetEcommerceBillFundflowBillResponse : WechatTenpayResponse
|
||||
{
|
||||
public static class Types
|
||||
|
@ -5,6 +5,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /ecommerce/profitsharing/orders 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class CreateEcommerceProfitSharingOrderRequest : WechatTenpayRequest
|
||||
{
|
||||
public static class Types
|
||||
|
@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /ecommerce/profitsharing/receivers/add 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class AddEcommerceProfitSharingReceiverRequest : WechatTenpayRequest
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /merchant-service/complaints-v2/{complaint_id} 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class GetMerchantServiceComplaintByComplaintIdResponse : WechatTenpayResponse
|
||||
{
|
||||
public static class Types
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /merchant-service/complaints-v2 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class QueryMerchantServiceComplaintsResponse : WechatTenpayResponse
|
||||
{
|
||||
public static class Types
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /partner-transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no} 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class GetPartnerTransferBatchDetailByOutDetailNumberResponse : GetTransferBatchDetailByOutDetailNumberResponse
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /payscore/merchant-bill 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class GetPayScoreMerchantBillResponse : WechatTenpayResponse
|
||||
{
|
||||
public static class Types
|
||||
|
@ -5,6 +5,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /profitsharing/orders 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class CreateProfitSharingOrderRequest : WechatTenpayRequest
|
||||
{
|
||||
public static class Types
|
||||
|
@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /profitsharing/receivers/add 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class AddProfitSharingReceiverRequest : WechatTenpayRequest
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /profitsharing/receivers/add 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class AddProfitSharingReceiverResponse : WechatTenpayResponse
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /smartguide/guides 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class CreateSmartGuideRequest : WechatTenpayRequest
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /smartguide/guides 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class QuerySmartGuidesRequest : WechatTenpayRequest
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /smartguide/guides 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class QuerySmartGuidesResponse : WechatTenpayResponse
|
||||
{
|
||||
public static class Types
|
||||
|
@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// <para>表示 [PATCH] /smartguide/guides/{guide_id} 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class UpdateSmartGuideRequest : WechatTenpayRequest
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -5,6 +5,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [POST] /transfer/batches 接口的请求。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class CreateTransferBatchRequest : WechatTenpayRequest
|
||||
{
|
||||
public static class Types
|
||||
|
@ -6,6 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
|
||||
/// <summary>
|
||||
/// <para>表示 [GET] /transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no} 接口的响应。</para>
|
||||
/// </summary>
|
||||
[WechatTenpaySensitive]
|
||||
public class GetTransferBatchDetailByOutDetailNumberResponse : WechatTenpayResponse
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -66,6 +66,9 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
if (objType.IsArray)
|
||||
{
|
||||
var array = (obj as Array)!;
|
||||
if (array.IsReadOnly)
|
||||
return;
|
||||
|
||||
for (int i = 0, len = array.Length; i < len; i++)
|
||||
{
|
||||
object? element = array.GetValue(i);
|
||||
@ -77,9 +80,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
{
|
||||
if (currentProp == null)
|
||||
continue;
|
||||
if (!currentProp.CanWrite)
|
||||
continue;
|
||||
|
||||
string oldValue = (string)element!;
|
||||
string newValue = replacement(obj, currentProp, oldValue);
|
||||
string newValue = replacement(obj!, currentProp, oldValue);
|
||||
array.SetValue(newValue, i);
|
||||
}
|
||||
else if (elementType.IsClass)
|
||||
@ -93,8 +98,12 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (obj is IList list)
|
||||
else if (obj is IList)
|
||||
{
|
||||
var list = (obj as IList)!;
|
||||
if (list.IsReadOnly)
|
||||
return;
|
||||
|
||||
for (int i = 0, len = list.Count; i < len; i++)
|
||||
{
|
||||
object? element = list[i];
|
||||
@ -106,6 +115,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
{
|
||||
if (currentProp == null)
|
||||
continue;
|
||||
if (!currentProp.CanWrite)
|
||||
continue;
|
||||
|
||||
string oldValue = (string)element!;
|
||||
string newValue = replacement(obj, currentProp, oldValue);
|
||||
@ -122,8 +133,12 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (obj is IDictionary dict)
|
||||
else if (obj is IDictionary)
|
||||
{
|
||||
var dict = (obj as IDictionary)!;
|
||||
if (dict.IsReadOnly)
|
||||
return;
|
||||
|
||||
foreach (DictionaryEntry entry in dict)
|
||||
{
|
||||
object? entryValue = entry.Value;
|
||||
@ -135,6 +150,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
{
|
||||
if (currentProp == null)
|
||||
continue;
|
||||
if (!currentProp.CanWrite)
|
||||
continue;
|
||||
|
||||
string oldValue = (string)entryValue!;
|
||||
string newValue = replacement(obj, currentProp, oldValue);
|
||||
|
Loading…
Reference in New Issue
Block a user