2022-11-13 23:17:18 +08:00
using System ;
2023-03-30 21:40:48 +08:00
using System.Collections.Generic ;
2021-11-25 18:42:54 +08:00
using System.Linq ;
using System.Reflection ;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{
2023-03-30 21:40:48 +08:00
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings ;
2024-02-04 11:39:32 +08:00
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities ;
2023-03-30 21:40:48 +08:00
2021-11-25 18:42:54 +08:00
public static class WechatTenpayClientRequestEncryptionExtensions
{
2024-02-04 11:39:32 +08:00
/// <summary>
/// <para>加密请求中传入的敏感数据。该方法会改变传入的请求模型对象。</para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <returns></returns>
public static TRequest EncryptRequestSensitiveProperty < TRequest > ( this WechatTenpayClient client , TRequest request )
2022-11-13 23:17:18 +08:00
where TRequest : WechatTenpayRequest
{
2024-02-04 11:39:32 +08:00
if ( client is null ) throw new ArgumentNullException ( nameof ( client ) ) ;
if ( request is null ) throw new ArgumentNullException ( nameof ( request ) ) ;
2022-11-13 23:17:18 +08:00
2024-02-04 11:39:32 +08:00
try
{
bool requireEncrypt = request . GetType ( ) . IsDefined ( typeof ( WechatTenpaySensitiveAttribute ) ) ;
if ( ! requireEncrypt )
return request ;
2022-11-13 23:17:18 +08:00
2024-02-04 11:39:32 +08:00
string signScheme = client . Credentials . SignScheme ;
string algorithmType = // 签名方式与加密算法保持一致: RSA_SHA256 签名需 RSA 加密, SM3 签名需 SM2 加密
Constants . SignSchemes . WECHATPAY2_RSA_2048_WITH_SHA256 . Equals ( signScheme ) ? CertificateEntry . ALGORITHM_TYPE_RSA :
Constants . SignSchemes . WECHATPAY2_SM2_WITH_SM3 . Equals ( signScheme ) ? CertificateEntry . ALGORITHM_TYPE_SM2 :
throw new WechatTenpayException ( $"Failed to encrypt request. Unsupported signing scheme: \" { signScheme } \ "." ) ;
2022-11-13 23:17:18 +08:00
2024-02-04 11:39:32 +08:00
ReflectionHelper . ReplaceObjectStringProperties ( request , ( _ , currentProp , oldValue ) = >
2022-11-13 23:17:18 +08:00
{
2024-02-04 11:39:32 +08:00
if ( currentProp is null | | ! currentProp . IsDefined ( typeof ( WechatTenpaySensitivePropertyAttribute ) ) )
return ( false , oldValue ) ;
2022-11-13 23:17:18 +08:00
2024-02-04 11:39:32 +08:00
WechatTenpaySensitivePropertyAttribute ? attribute = currentProp
. GetCustomAttributes < WechatTenpaySensitivePropertyAttribute > ( )
. FirstOrDefault ( attr = > attr . Scheme = = signScheme ) ;
if ( attribute is null )
return ( false , oldValue ) ;
2022-11-13 23:17:18 +08:00
2024-02-04 11:39:32 +08:00
string certificate ;
if ( string . IsNullOrEmpty ( request . WechatpayCertificateSerialNumber ) )
{
if ( client . PlatformCertificateManager is null )
throw new WechatTenpayException ( "Failed to encrypt request, because the platform certificate manager is not initialized." ) ;
// 如果未在请求中指定特定的平台证书序列号,从管理器中取过期时间最远的
IEnumerable < CertificateEntry > entries = client . PlatformCertificateManager . AllEntries ( )
. Where ( e = > e . AlgorithmType = = algorithmType )
. OrderByDescending ( e = > e . ExpireTime ) ;
if ( ! entries . Any ( ) )
2022-11-13 23:17:18 +08:00
{
2024-02-04 11:39:32 +08:00
throw new WechatTenpayException ( "Failed to encrypt request, because the platform certificate manager is empty. Please make sure you have downloaded platform (NOT merchant) certificates first." ) ;
2022-11-13 23:17:18 +08:00
}
2024-02-04 11:39:32 +08:00
CertificateEntry entry = entries . First ( ) ;
certificate = entry . Certificate ;
request . WechatpayCertificateSerialNumber = entry . SerialNumber ;
2022-11-13 23:17:18 +08:00
}
2024-02-04 11:39:32 +08:00
else
2022-11-13 23:17:18 +08:00
{
2024-02-04 11:39:32 +08:00
// 如果已在请求中指定特定的平台证书序列号,直接从管理器中取值
CertificateEntry ? entry = client . PlatformCertificateManager ? . GetEntry ( request . WechatpayCertificateSerialNumber ! ) ;
if ( ! entry . HasValue )
2022-11-13 23:17:18 +08:00
{
2024-02-04 11:39:32 +08:00
throw new WechatTenpayException ( $"Failed to encrypt request, because the platform certificate manager does not contain a certificate matched the serial number \" { request . WechatpayCertificateSerialNumber } \ ". Please make sure you have downloaded platform (NOT merchant) certificates first." ) ;
2022-11-13 23:17:18 +08:00
}
2024-02-04 11:39:32 +08:00
certificate = entry . Value . Certificate ;
}
2021-11-25 18:42:54 +08:00
2024-02-04 11:39:32 +08:00
string newValue ;
switch ( attribute . Algorithm )
2021-11-25 18:42:54 +08:00
{
2024-02-04 11:39:32 +08:00
case Constants . EncryptionAlgorithms . RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1 :
{
newValue = RSAUtility . EncryptWithECBByCertificate (
2024-02-05 10:53:59 +08:00
certificatePem : certificate ,
plainData : oldValue ,
paddingMode : RSAUtility . PADDING_MODE_OAEPWITHSHA1ANDMGF1
) ! ;
2024-02-04 11:39:32 +08:00
}
break ;
case Constants . EncryptionAlgorithms . RSA_2048_ECB_PKCS1 :
{
newValue = RSAUtility . EncryptWithECBByCertificate (
2024-02-05 10:53:59 +08:00
certificatePem : certificate ,
plainData : oldValue ,
paddingMode : RSAUtility . PADDING_MODE_PKCS1
) ! ;
2024-02-04 11:39:32 +08:00
}
break ;
case Constants . EncryptionAlgorithms . SM2_C1C3C2_ASN1 :
{
newValue = SM2Utility . EncryptByCertificate (
2024-02-05 10:53:59 +08:00
certificatePem : certificate ,
plainData : oldValue ,
2024-02-04 11:39:32 +08:00
asn1Encoding : true
2024-02-05 10:53:59 +08:00
) ! ;
2024-02-04 11:39:32 +08:00
}
break ;
default :
{
throw new WechatTenpayException ( $"Failed to encrypt request. Unsupported encryption algorithm: \" { attribute . Algorithm } \ "." ) ;
}
2022-11-13 23:17:18 +08:00
}
2024-02-04 11:39:32 +08:00
return ( true , newValue ) ;
} ) ;
2022-11-13 23:17:18 +08:00
return request ;
2021-11-25 18:42:54 +08:00
}
2022-11-13 23:17:18 +08:00
catch ( WechatTenpayException )
{
throw ;
}
catch ( Exception ex )
2021-11-25 18:42:54 +08:00
{
2024-01-29 23:12:37 +08:00
throw new WechatTenpayException ( "Failed to encrypt request. Please see the inner exception for more details." , ex ) ;
2021-11-25 18:42:54 +08:00
}
}
}
}