DotNetCore.SKIT.FlurlHttpCl.../src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseDecryptionExtensions.cs

88 lines
4.0 KiB
C#
Raw Normal View History

2021-05-10 15:30:00 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
2021-05-10 15:30:00 +08:00
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{
/// <summary>
/// 为 <see cref="WechatTenpayClient"/> 提供响应敏感数据解密的扩展方法。
/// </summary>
public static class WechatTenpayClientResponseDecryptionExtensions
{
/// <summary>
/// <para>解密响应中返回的敏感数据。该方法会改变传入的响应信息。</para>
/// </summary>
/// <param name="client"></param>
/// <param name="response"></param>
/// <returns></returns>
public static TResponse DecryptResponseSensitiveProperty<TResponse>(this WechatTenpayClient client, TResponse response)
where TResponse : WechatTenpayResponse
2021-05-10 15:30:00 +08:00
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (response == null) throw new ArgumentNullException(nameof(response));
if (string.IsNullOrEmpty(client.Credentials.MerchantCertPrivateKey))
2021-07-30 20:08:23 +08:00
throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because there is no merchant private key.");
2021-05-10 15:30:00 +08:00
if (!response.IsSuccessful())
2021-07-30 20:08:23 +08:00
throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because the response is not successful.");
2021-05-10 15:30:00 +08:00
try
2021-05-10 15:30:00 +08:00
{
// [GET] /certificates 接口的响应模型需特殊处理
if (response is Models.QueryCertificatesResponse queryCertificatesResponse)
2021-05-10 15:30:00 +08:00
{
if (queryCertificatesResponse.CertificateList == null)
return response;
2021-05-10 15:30:00 +08:00
foreach (var certificateModel in queryCertificatesResponse.CertificateList)
2021-05-10 15:30:00 +08:00
{
if (Constants.EncryptionAlgorithms.AEAD_AES_256_GCM.Equals(certificateModel.EncryptCertificate?.Algorithm))
2021-05-10 15:30:00 +08:00
{
certificateModel.EncryptCertificate.CipherText = Utilities.AESUtility.DecryptWithGCM(
key: client.Credentials.MerchantV3Secret,
iv: certificateModel.EncryptCertificate.Nonce,
aad: certificateModel.EncryptCertificate.AssociatedData,
2021-05-10 15:30:00 +08:00
cipherText: certificateModel.EncryptCertificate.CipherText
);
}
else
2021-05-10 15:30:00 +08:00
{
throw new Exceptions.WechatTenpayResponseDecryptionException("Unsupported decryption algorithm.");
2021-05-10 15:30:00 +08:00
}
}
return response;
2021-05-10 15:30:00 +08:00
}
// 遍历并解密被标记为敏感数据的字段
Utilities.ReflectionUtility.ReplacePropertyStringValue(ref response, (obj, prop, value) =>
2021-05-10 15:30:00 +08:00
{
var attr = prop.GetCustomAttribute<WechatTenpaySensitivePropertyAttribute>();
if (attr == null)
return value;
if (Constants.EncryptionAlgorithms.RSA_2048_PKCS8_ECB.Equals(attr.Algorithm))
2021-05-10 15:30:00 +08:00
{
return Utilities.RSAUtility.DecryptWithECB(
privateKey: client.Credentials.MerchantCertPrivateKey,
cipherText: value
);
2021-05-10 15:30:00 +08:00
}
else
2021-05-10 15:30:00 +08:00
{
throw new Exceptions.WechatTenpayResponseDecryptionException("Unsupported decryption algorithm.");
2021-05-10 15:30:00 +08:00
}
});
}
catch (Exception ex) when (!(ex is Exceptions.WechatTenpayResponseDecryptionException))
{
throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed. Please see the `InnerException` for more details.", ex);
}
return response;
}
2021-05-10 15:30:00 +08:00
}
}