diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/ExtendedSDK/Global/WechatTenpayGlobalClient.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/ExtendedSDK/Global/WechatTenpayGlobalClient.cs
index a26c639b..5ffbe0d1 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/ExtendedSDK/Global/WechatTenpayGlobalClient.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/ExtendedSDK/Global/WechatTenpayGlobalClient.cs
@@ -69,7 +69,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.ExtendedSDK.Global
PlatformAuthScheme = _ROOT_.Settings.PlatformAuthScheme.Certificate,
PlatformCertificateManager = options.PlatformCertificateManager,
AutoEncryptRequestSensitiveProperty = options.AutoEncryptRequestSensitiveProperty,
- AutoDecryptResponseSensitiveProperty = options.AutoDecryptResponseSensitiveProperty
+ AutoDecryptResponseSensitiveProperty = options.AutoDecryptResponseSensitiveProperty,
}, httpClient, disposeClient);
Credentials = new Settings.Credentials(options);
@@ -100,7 +100,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.ExtendedSDK.Global
///
public IFlurlRequest CreateFlurlRequest(WechatTenpayGlobalRequest request, HttpMethod httpMethod, params object[] urlSegments)
{
- return base.CreateFlurlRequest(request, httpMethod, urlSegments);
+ return ProxyClient.CreateFlurlRequest(request, httpMethod, urlSegments);
}
///
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs
index b609abec..49a792e5 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs
@@ -61,7 +61,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{
if (client is null) throw new ArgumentNullException(nameof(client));
- return WechatTenpayClientSigningExtensions.VerifySignature(
+ return WechatTenpayClientSigningExtensions._VerifySignature(
client,
strTimestamp: webhookTimestamp,
strNonce: webhookNonce,
@@ -127,7 +127,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{
if (client is null) throw new ArgumentNullException(nameof(client));
- return WechatTenpayClientSigningExtensions.VerifySignatureAsync(
+ return WechatTenpayClientSigningExtensions._VerifySignatureAsync(
client,
strTimestamp: webhookTimestamp,
strNonce: webhookNonce,
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientRequestEncryptionExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientRequestEncryptionExtensions.cs
index 7745e351..255c45e8 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientRequestEncryptionExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientRequestEncryptionExtensions.cs
@@ -25,16 +25,37 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
- switch (client.PlatformAuthScheme)
+ bool required = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
+ if (!required)
+ return request;
+
+ try
{
- case PlatformAuthScheme.Certificate:
- return EncryptRequestSensitivePropertyByCertificate(client, request);
+ switch (client.PlatformAuthScheme)
+ {
+ case PlatformAuthScheme.Certificate:
+ {
+ WechatTenpayClientRequestSerialNumberExtensions._EnsureRequestWechatpaySerialNumberIsSet(client, request);
+ return EncryptRequestSensitivePropertyUseCertificateManager(client.PlatformCertificateManager, client.Credentials.SignScheme, request);
+ }
- case PlatformAuthScheme.PublicKey:
- return EncryptRequestSensitivePropertyByPublicKey(client, request);
+ case PlatformAuthScheme.PublicKey:
+ {
+ WechatTenpayClientRequestSerialNumberExtensions._EnsureRequestWechatpaySerialNumberIsSet(client, request);
+ return EncryptRequestSensitivePropertyUsePublicKeyManager(client.PlatformPublicKeyManager, client.Credentials.SignScheme, request);
+ }
- default:
- throw new WechatTenpayException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\".");
+ default:
+ throw new NotSupportedException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\".");
+ }
+ }
+ catch (WechatTenpayException)
+ {
+ throw;
+ }
+ catch (Exception ex)
+ {
+ throw new WechatTenpayException("Failed to encrypt request. Please see the inner exception for more details.", ex);
}
}
@@ -45,84 +66,47 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
///
///
- public static Task EncryptRequestSensitivePropertyAsync(this WechatTenpayClient client, TRequest request, CancellationToken cancellationToken = default)
+ public static async Task EncryptRequestSensitivePropertyAsync(this WechatTenpayClient client, TRequest request, CancellationToken cancellationToken = default)
where TRequest : WechatTenpayRequest
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
- switch (client.PlatformAuthScheme)
- {
- case PlatformAuthScheme.Certificate:
- return EncryptRequestSensitivePropertyByCertificateAsync(client, request);
+ bool required = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
+ if (!required)
+ return request;
- case PlatformAuthScheme.PublicKey:
- return EncryptRequestSensitivePropertyByPublicKeyAsync(client, request);
-
- default:
- throw new WechatTenpayException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\".");
- }
- }
-
- private static TRequest EncryptRequestSensitivePropertyByCertificate(this WechatTenpayClient client, TRequest request)
- where TRequest : WechatTenpayRequest
- {
try
{
- bool requireEncrypt = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
- if (!requireEncrypt)
- return request;
-
- string signScheme = client.Credentials.SignScheme;
- string algorithmType = // 签名方式与加密算法保持一致:RSA_SHA256 签名需 RSA 加密,SM3 签名需 SM2 加密
- SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256.Equals(signScheme) ? CertificateEntry.ALGORITHM_TYPE_RSA :
- SignSchemes.WECHATPAY2_SM2_WITH_SM3.Equals(signScheme) ? CertificateEntry.ALGORITHM_TYPE_SM2 :
- throw new WechatTenpayException($"Failed to encrypt request. Unsupported signing scheme: \"{signScheme}\".");
-
- string certificate;
- if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
+ switch (client.PlatformAuthScheme)
{
- // 如果未在请求中指定特定的平台证书序列号,从管理器中取过期时间最远的
- IEnumerable entries = client.PlatformCertificateManager.AllEntries()
- .Where(e => e.AlgorithmType == algorithmType)
- .OrderByDescending(e => e.ExpireTime);
- if (!entries.Any())
- {
- 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.");
- }
+ case PlatformAuthScheme.Certificate:
+ {
+ if (client.PlatformCertificateManager is not ICertificateManagerAsync)
+ {
+ // 降级为同步调用
+ return EncryptRequestSensitivePropertyUseCertificateManager(client.PlatformCertificateManager, client.Credentials.SignScheme, request);
+ }
- CertificateEntry entry = entries.First();
- certificate = entry.Certificate;
- request.WechatpaySerialNumber = entry.SerialNumber;
+ await WechatTenpayClientRequestSerialNumberExtensions._EnsureRequestWechatpaySerialNumberIsSetAsync(client, request, cancellationToken).ConfigureAwait(false);
+ return await EncryptRequestSensitivePropertyUseCertificateManagerAsync((ICertificateManagerAsync)client.PlatformCertificateManager, client.Credentials.SignScheme, request, cancellationToken).ConfigureAwait(false);
+ }
+
+ case PlatformAuthScheme.PublicKey:
+ {
+ if (client.PlatformPublicKeyManager is not IPublicKeyManagerAsync)
+ {
+ // 降级为同步调用
+ return EncryptRequestSensitivePropertyUsePublicKeyManager(client.PlatformPublicKeyManager, client.Credentials.SignScheme, request);
+ }
+
+ await WechatTenpayClientRequestSerialNumberExtensions._EnsureRequestWechatpaySerialNumberIsSetAsync(client, request, cancellationToken).ConfigureAwait(false);
+ return await EncryptRequestSensitivePropertyUsePublicKeyManagerAsync((IPublicKeyManagerAsync)client.PlatformPublicKeyManager, client.Credentials.SignScheme, request, cancellationToken).ConfigureAwait(false);
+ }
+
+ default:
+ throw new NotSupportedException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\".");
}
- else
- {
- // 如果已在请求中指定特定的平台证书序列号,直接从管理器中取值
- CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(request.WechatpaySerialNumber!);
- if (!entry.HasValue)
- {
- throw new WechatTenpayException($"Failed to encrypt request, because the platform certificate manager does not contain a certificate matched the serial number \"{request.WechatpaySerialNumber}\". Please make sure you have downloaded platform (NOT merchant) certificates first.");
- }
-
- certificate = entry.Value.Certificate;
- }
-
- ReflectionHelper.ReplaceObjectStringProperties(request, (_, currentProp, oldValue) =>
- {
- if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
- return (false, oldValue);
-
- WechatTenpaySensitivePropertyAttribute? attribute = currentProp
- .GetCustomAttributes()
- .FirstOrDefault(attr => attr.Scheme == signScheme);
- if (attribute is null)
- return (false, oldValue);
-
- string newValue = GenerateEncryptedValueByCertificate(attribute.Algorithm, certificate, oldValue);
- return (true, newValue);
- });
-
- return request;
}
catch (WechatTenpayException)
{
@@ -134,281 +118,128 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
}
}
- private static async Task EncryptRequestSensitivePropertyByCertificateAsync(this WechatTenpayClient client, TRequest request, CancellationToken cancellationToken = default)
+ private static TRequest EncryptRequestSensitivePropertyUseCertificateManager(ICertificateManager manager, string signScheme, TRequest request)
where TRequest : WechatTenpayRequest
{
- if (client.PlatformCertificateManager is not ICertificateManagerAsync)
- {
- // 降级为同步调用
- return EncryptRequestSensitivePropertyByCertificate(client, request);
- }
+ if (manager is null)
+ throw new NullReferenceException("The platform certificate manager is not configured.");
- try
- {
- bool requireEncrypt = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
- if (!requireEncrypt)
- return request;
+ CertificateEntry? entry = manager.GetEntry(request.WechatpaySerialNumber!);
+ if (!entry.HasValue)
+ throw new WechatTenpayException($"Failed to encrypt request, because the platform certificate manager does not contain a certificate matched the serial number \"{request.WechatpaySerialNumber}\". Please make sure you have downloaded platform (NOT merchant) certificates first.");
- string signScheme = client.Credentials.SignScheme;
- string algorithmType = // 签名方式与加密算法保持一致:RSA_SHA256 签名需 RSA 加密,SM3 签名需 SM2 加密
- SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256.Equals(signScheme) ? CertificateEntry.ALGORITHM_TYPE_RSA :
- SignSchemes.WECHATPAY2_SM2_WITH_SM3.Equals(signScheme) ? CertificateEntry.ALGORITHM_TYPE_SM2 :
- throw new WechatTenpayException($"Failed to encrypt request. Unsupported signing scheme: \"{signScheme}\".");
-
- string certificate;
- if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
- {
- if (client.PlatformCertificateManager is null)
- throw new WechatTenpayException("Failed to encrypt request, because the platform certificate manager is not initialized.");
-
- // 如果未在请求中指定特定的平台证书序列号,从管理器中取过期时间最远的
- IEnumerable entries = await ((ICertificateManagerAsync)client.PlatformCertificateManager).AllEntriesAsync(cancellationToken).ConfigureAwait(false);
- entries = entries.Where(e => e.AlgorithmType == algorithmType).OrderByDescending(e => e.ExpireTime);
- if (!entries.Any())
- {
- 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.");
- }
-
- CertificateEntry entry = entries.First();
- certificate = entry.Certificate;
- request.WechatpaySerialNumber = entry.SerialNumber;
- }
- else
- {
- // 如果已在请求中指定特定的平台证书序列号,直接从管理器中取值
- CertificateEntry? entry = await ((ICertificateManagerAsync)client.PlatformCertificateManager).GetEntryAsync(request.WechatpaySerialNumber!, cancellationToken).ConfigureAwait(false);
- if (!entry.HasValue)
- {
- throw new WechatTenpayException($"Failed to encrypt request, because the platform certificate manager does not contain a certificate matched the serial number \"{request.WechatpaySerialNumber}\". Please make sure you have downloaded platform (NOT merchant) certificates first.");
- }
-
- certificate = entry.Value.Certificate;
- }
-
- ReflectionHelper.ReplaceObjectStringProperties(request, (_, currentProp, oldValue) =>
- {
- if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
- return (false, oldValue);
-
- WechatTenpaySensitivePropertyAttribute? attribute = currentProp
- .GetCustomAttributes()
- .FirstOrDefault(attr => attr.Scheme == signScheme);
- if (attribute is null)
- return (false, oldValue);
-
- string newValue = GenerateEncryptedValueByCertificate(attribute.Algorithm, certificate, oldValue);
- return (true, newValue);
- });
-
- return request;
- }
- catch (WechatTenpayException)
- {
- throw;
- }
- catch (Exception ex)
- {
- throw new WechatTenpayException("Failed to encrypt request. Please see the inner exception for more details.", ex);
- }
+ return PopulateRequestEncryptedFieldsByCertificate(signScheme, entry.Value.Certificate, ref request);
}
- private static TRequest EncryptRequestSensitivePropertyByPublicKey(this WechatTenpayClient client, TRequest request)
+ private static async Task EncryptRequestSensitivePropertyUseCertificateManagerAsync(ICertificateManagerAsync manager, string signScheme, TRequest request, CancellationToken cancellationToken = default)
where TRequest : WechatTenpayRequest
{
- try
- {
- bool requireEncrypt = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
- if (!requireEncrypt)
- return request;
+ if (manager is null)
+ throw new NullReferenceException("The platform certificate manager is not configured.");
- string signScheme = client.Credentials.SignScheme;
- string algorithmType = // 签名方式与加密算法保持一致:RSA_SHA256 签名需 RSA 加密,SM3 签名需 SM2 加密
- SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256.Equals(signScheme) ? PublicKeyEntry.ALGORITHM_TYPE_RSA :
- SignSchemes.WECHATPAY2_SM2_WITH_SM3.Equals(signScheme) ? PublicKeyEntry.ALGORITHM_TYPE_SM2 :
- throw new WechatTenpayException($"Failed to encrypt request. Unsupported signing scheme: \"{signScheme}\".");
+ CertificateEntry? entry = await manager.GetEntryAsync(request.WechatpaySerialNumber!, cancellationToken).ConfigureAwait(false);
+ if (!entry.HasValue)
+ throw new WechatTenpayException($"Failed to encrypt request, because the platform certificate manager does not contain a certificate matched the serial number \"{request.WechatpaySerialNumber}\". Please make sure you have downloaded platform (NOT merchant) certificates first.");
- string publicKey;
- if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
- {
- // 如果未在请求中指定特定的平台公钥 ID,从管理器中取第一个
- IEnumerable entries = client.PlatformPublicKeyManager.AllEntries()
- .Where(e => e.AlgorithmType == algorithmType);
- if (!entries.Any())
- {
- throw new WechatTenpayException("Failed to encrypt request, because the platform public key manager is empty.");
- }
-
- PublicKeyEntry entry = entries.First();
- publicKey = entry.PublicKey;
- request.WechatpaySerialNumber = entry.SerialNumber;
- }
- else
- {
- // 如果已在请求中指定特定的平台公钥 ID,直接从管理器中取值
- PublicKeyEntry? entry = client.PlatformPublicKeyManager.GetEntry(request.WechatpaySerialNumber!);
- if (!entry.HasValue)
- {
- throw new WechatTenpayException($"Failed to encrypt request, because the platform public key manager does not contain a key matched the serial number \"{request.WechatpaySerialNumber}\".");
- }
-
- publicKey = entry.Value.PublicKey;
- }
-
- ReflectionHelper.ReplaceObjectStringProperties(request, (_, currentProp, oldValue) =>
- {
- if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
- return (false, oldValue);
-
- WechatTenpaySensitivePropertyAttribute? attribute = currentProp
- .GetCustomAttributes()
- .FirstOrDefault(attr => attr.Scheme == signScheme);
- if (attribute is null)
- return (false, oldValue);
-
- string newValue = GenerateEncryptedValueByPublicKey(attribute.Algorithm, publicKey, oldValue);
- return (true, newValue);
- });
-
- return request;
- }
- catch (WechatTenpayException)
- {
- throw;
- }
- catch (Exception ex)
- {
- throw new WechatTenpayException("Failed to encrypt request. Please see the inner exception for more details.", ex);
- }
+ return PopulateRequestEncryptedFieldsByCertificate(signScheme, entry.Value.Certificate, ref request);
}
- private static async Task EncryptRequestSensitivePropertyByPublicKeyAsync(this WechatTenpayClient client, TRequest request, CancellationToken cancellationToken = default)
+ private static TRequest EncryptRequestSensitivePropertyUsePublicKeyManager(IPublicKeyManager manager, string signScheme, TRequest request)
where TRequest : WechatTenpayRequest
{
- if (client.PlatformPublicKeyManager is not IPublicKeyManagerAsync)
- {
- // 降级为同步调用
- return EncryptRequestSensitivePropertyByPublicKey(client, request);
- }
+ if (manager is null)
+ throw new NullReferenceException("The platform public key manager is not configured.");
- try
- {
- bool requireEncrypt = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
- if (!requireEncrypt)
- return request;
+ PublicKeyEntry? entry = manager.GetEntry(request.WechatpaySerialNumber!);
+ if (!entry.HasValue)
+ throw new WechatTenpayException($"Failed to encrypt request, because the platform public key manager does not contain a key matched the serial number \"{request.WechatpaySerialNumber}\".");
- string signScheme = client.Credentials.SignScheme;
- string algorithmType = // 签名方式与加密算法保持一致:RSA_SHA256 签名需 RSA 加密,SM3 签名需 SM2 加密
- SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256.Equals(signScheme) ? PublicKeyEntry.ALGORITHM_TYPE_RSA :
- SignSchemes.WECHATPAY2_SM2_WITH_SM3.Equals(signScheme) ? PublicKeyEntry.ALGORITHM_TYPE_SM2 :
- throw new WechatTenpayException($"Failed to encrypt request. Unsupported signing scheme: \"{signScheme}\".");
-
- string publicKey;
- if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
- {
- if (client.PlatformPublicKeyManager is null)
- throw new WechatTenpayException("Failed to encrypt request, because the platform public key manager is not initialized.");
-
- // 如果未在请求中指定特定的平台公钥 ID,从管理器中第一个
- IEnumerable entries = await ((IPublicKeyManagerAsync)client.PlatformPublicKeyManager).AllEntriesAsync(cancellationToken).ConfigureAwait(false);
- entries = entries.Where(e => e.AlgorithmType == algorithmType);
- if (!entries.Any())
- {
- throw new WechatTenpayException("Failed to encrypt request, because the platform public key manager is empty.");
- }
-
- PublicKeyEntry entry = entries.First();
- publicKey = entry.PublicKey;
- request.WechatpaySerialNumber = entry.SerialNumber;
- }
- else
- {
- // 如果已在请求中指定特定的平台公钥 ID,直接从管理器中取值
- PublicKeyEntry? entry = await ((IPublicKeyManagerAsync)client.PlatformPublicKeyManager).GetEntryAsync(request.WechatpaySerialNumber!, cancellationToken).ConfigureAwait(false);
- if (!entry.HasValue)
- {
- throw new WechatTenpayException($"Failed to encrypt request, because the platform public key manager does not contain a key matched the serial number \"{request.WechatpaySerialNumber}\".");
- }
-
- publicKey = entry.Value.PublicKey;
- }
-
- ReflectionHelper.ReplaceObjectStringProperties(request, (_, currentProp, oldValue) =>
- {
- if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
- return (false, oldValue);
-
- WechatTenpaySensitivePropertyAttribute? attribute = currentProp
- .GetCustomAttributes()
- .FirstOrDefault(attr => attr.Scheme == signScheme);
- if (attribute is null)
- return (false, oldValue);
-
- string newValue = GenerateEncryptedValueByPublicKey(attribute.Algorithm, publicKey, oldValue);
- return (true, newValue);
- });
-
- return request;
- }
- catch (WechatTenpayException)
- {
- throw;
- }
- catch (Exception ex)
- {
- throw new WechatTenpayException("Failed to encrypt request. Please see the inner exception for more details.", ex);
- }
+ return PopulateRequestEncryptedFieldsByPublicKey(signScheme, entry.Value.PublicKey, ref request);
}
- private static string GenerateEncryptedValueByCertificate(string algorithm, string certificate, string value)
+ private static async Task EncryptRequestSensitivePropertyUsePublicKeyManagerAsync(IPublicKeyManagerAsync manager, string signScheme, TRequest request, CancellationToken cancellationToken = default)
+ where TRequest : WechatTenpayRequest
{
- switch (algorithm)
+ if (manager is null)
+ throw new NullReferenceException("The platform public key manager is not configured.");
+
+ PublicKeyEntry? entry = await manager.GetEntryAsync(request.WechatpaySerialNumber!, cancellationToken).ConfigureAwait(false);
+ if (!entry.HasValue)
+ throw new WechatTenpayException($"Failed to encrypt request, because the platform public key manager does not contain a key matched the serial number \"{request.WechatpaySerialNumber}\".");
+
+ return PopulateRequestEncryptedFieldsByPublicKey(signScheme, entry.Value.PublicKey, ref request);
+ }
+
+ private static TRequest PopulateRequestEncryptedFieldsByCertificate(string scheme, string certificate, ref TRequest request)
+ where TRequest : WechatTenpayRequest
+ {
+ switch (scheme)
{
- case EncryptionAlgorithms.RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1:
- case EncryptionAlgorithms.RSA_2048_ECB_PKCS1:
+ case SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256:
{
string publicKey = RSAUtility.ExportPublicKeyFromCertificate(certificate);
- return GenerateEncryptedValueByPublicKey(algorithm, publicKey, value);
+ return PopulateRequestEncryptedFieldsByPublicKey(scheme, publicKey, ref request);
}
- case EncryptionAlgorithms.SM2_C1C3C2_ASN1:
+ case SignSchemes.WECHATPAY2_SM2_WITH_SM3:
{
string publicKey = SM2Utility.ExportPublicKeyFromCertificate(certificate);
- return GenerateEncryptedValueByPublicKey(algorithm, publicKey, value);
+ return PopulateRequestEncryptedFieldsByPublicKey(scheme, publicKey, ref request);
}
default:
- throw new WechatTenpayException($"Failed to encrypt request. Unsupported encryption algorithm: \"{algorithm}\".");
+ throw new NotSupportedException($"Unsupported signing scheme: \"{scheme}\".");
}
}
- private static string GenerateEncryptedValueByPublicKey(string algorithm, string publicKey, string value)
+ private static TRequest PopulateRequestEncryptedFieldsByPublicKey(string scheme, string publicKey, ref TRequest request)
+ where TRequest : WechatTenpayRequest
{
- switch (algorithm)
+ ReflectionHelper.ReplaceObjectStringProperties(ref request, (_, currentProp, oldValue) =>
{
- case EncryptionAlgorithms.RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1:
- return RSAUtility.EncryptWithECB(
- publicKeyPem: publicKey,
- plainData: value,
- paddingMode: RSAUtility.PADDING_MODE_OAEPWITHSHA1ANDMGF1
- )!;
+ if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
+ return (false, oldValue);
- case EncryptionAlgorithms.RSA_2048_ECB_PKCS1:
- return RSAUtility.EncryptWithECB(
- publicKeyPem: publicKey,
- plainData: value,
- paddingMode: RSAUtility.PADDING_MODE_PKCS1
- )!;
+ WechatTenpaySensitivePropertyAttribute? attribute = currentProp
+ .GetCustomAttributes()
+ .FirstOrDefault(attr => attr.Scheme == scheme);
+ if (attribute is null)
+ return (false, oldValue);
- case EncryptionAlgorithms.SM2_C1C3C2_ASN1:
- return SM2Utility.Encrypt(
- publicKeyPem: publicKey,
- plainData: value,
- asn1Encoding: true
- )!;
+ string newValue;
+ switch (attribute.Algorithm)
+ {
+ case EncryptionAlgorithms.RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1:
+ newValue = RSAUtility.EncryptWithECB(
+ publicKeyPem: publicKey,
+ plainData: oldValue,
+ paddingMode: RSAUtility.PADDING_MODE_OAEPWITHSHA1ANDMGF1
+ )!;
+ break;
- default:
- throw new WechatTenpayException($"Failed to encrypt request. Unsupported encryption algorithm: \"{algorithm}\".");
- }
+ case EncryptionAlgorithms.RSA_2048_ECB_PKCS1:
+ newValue = RSAUtility.EncryptWithECB(
+ publicKeyPem: publicKey,
+ plainData: oldValue,
+ paddingMode: RSAUtility.PADDING_MODE_PKCS1
+ )!;
+ break;
+
+ case EncryptionAlgorithms.SM2_C1C3C2_ASN1:
+ newValue = SM2Utility.Encrypt(
+ publicKeyPem: publicKey,
+ plainData: oldValue,
+ asn1Encoding: true
+ )!;
+ break;
+
+ default:
+ throw new NotSupportedException($"Unsupported encryption algorithm: \"{attribute.Algorithm}\".");
+ }
+
+ return (true, newValue);
+ });
+ return request;
}
}
}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseDecryptionExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseDecryptionExtensions.cs
index 9ca3d798..102bf49e 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseDecryptionExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseDecryptionExtensions.cs
@@ -107,7 +107,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
string signScheme = client.Credentials.SignScheme;
- ReflectionHelper.ReplaceObjectStringProperties(response, (_, currentProp, oldValue) =>
+ ReflectionHelper.ReplaceObjectStringProperties(ref response, (_, currentProp, oldValue) =>
{
if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
return (false, oldValue);
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs
index 8e70d12d..fd9dc780 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs
@@ -93,7 +93,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{
if (client is null) throw new ArgumentNullException(nameof(client));
- return WechatTenpayClientSigningExtensions.VerifySignature(
+ return WechatTenpayClientSigningExtensions._VerifySignature(
client,
strTimestamp: responseTimestamp,
strNonce: responseNonce,
@@ -192,7 +192,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{
if (client is null) throw new ArgumentNullException(nameof(client));
- return WechatTenpayClientSigningExtensions.VerifySignatureAsync(
+ return WechatTenpayClientSigningExtensions._VerifySignatureAsync(
client,
strTimestamp: responseTimestamp,
strNonce: responseNonce,
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/[Internal]/WechatTenpayClientRequestSerialNumberExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/[Internal]/WechatTenpayClientRequestSerialNumberExtensions.cs
new file mode 100644
index 00000000..0a2c6c4b
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/[Internal]/WechatTenpayClientRequestSerialNumberExtensions.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
+{
+ using SKIT.FlurlHttpClient.Wechat.TenpayV3.Constants;
+ using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
+
+ internal static class WechatTenpayClientRequestSerialNumberExtensions
+ {
+ public static TRequest _EnsureRequestWechatpaySerialNumberIsSet(this WechatTenpayClient client, TRequest request)
+ where TRequest : WechatTenpayRequest
+ {
+ if (client is null) throw new ArgumentNullException(nameof(client));
+ if (request is null) throw new ArgumentNullException(nameof(request));
+
+ try
+ {
+ switch (client.PlatformAuthScheme)
+ {
+ case PlatformAuthScheme.Certificate:
+ return EnsureRequestWechatpaySerialNumberIsSetUseCertificateManager(client.PlatformCertificateManager, client.Credentials.SignScheme, request);
+
+ case PlatformAuthScheme.PublicKey:
+ return EnsureRequestWechatpaySerialNumberIsSetUsePublicKeyManager(client.PlatformPublicKeyManager, client.Credentials.SignScheme, request);
+
+ default:
+ throw new NotSupportedException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\".");
+ }
+ }
+ catch (WechatTenpayException)
+ {
+ throw;
+ }
+ catch (Exception ex)
+ {
+ throw new WechatTenpayException("Failed to set the wechatpay serial number of request. Please see the inner exception for more details.", ex);
+ }
+ }
+
+ public static async Task _EnsureRequestWechatpaySerialNumberIsSetAsync(this WechatTenpayClient client, TRequest request, CancellationToken cancellationToken = default)
+ where TRequest : WechatTenpayRequest
+ {
+ if (client is null) throw new ArgumentNullException(nameof(client));
+ if (request is null) throw new ArgumentNullException(nameof(request));
+
+ try
+ {
+ switch (client.PlatformAuthScheme)
+ {
+ case PlatformAuthScheme.Certificate:
+ {
+ if (client.PlatformCertificateManager is not ICertificateManagerAsync)
+ {
+ // 降级为同步调用
+ return EnsureRequestWechatpaySerialNumberIsSetUseCertificateManager(client.PlatformCertificateManager, client.Credentials.SignScheme, request);
+ }
+
+ return await EnsureRequestWechatpaySerialNumberIsSetUseCertificateManagerAsync((ICertificateManagerAsync)client.PlatformCertificateManager, client.Credentials.SignScheme, request).ConfigureAwait(false);
+ }
+
+ case PlatformAuthScheme.PublicKey:
+ {
+ if (client.PlatformPublicKeyManager is not IPublicKeyManagerAsync)
+ {
+ // 降级为同步调用
+ return EnsureRequestWechatpaySerialNumberIsSetUsePublicKeyManager(client.PlatformPublicKeyManager, client.Credentials.SignScheme, request);
+ }
+
+ return await EnsureRequestWechatpaySerialNumberIsSetUsePublicKeyManagerAsync((IPublicKeyManagerAsync)client.PlatformPublicKeyManager, client.Credentials.SignScheme, request).ConfigureAwait(false);
+ }
+
+ default:
+ throw new NotSupportedException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\".");
+ }
+ }
+ catch (WechatTenpayException)
+ {
+ throw;
+ }
+ catch (Exception ex)
+ {
+ throw new WechatTenpayException("Failed to set the wechatpay serial number of request. Please see the inner exception for more details.", ex);
+ }
+ }
+
+ private static bool TryGetAlgorithmType(string signScheme, out string algorithmType)
+ {
+ algorithmType = // 签名方式与加密算法保持一致:RSA_SHA256 签名需 RSA 加密,SM3 签名需 SM2 加密
+ SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256.Equals(signScheme) ? CertificateEntry.ALGORITHM_TYPE_RSA :
+ SignSchemes.WECHATPAY2_SM2_WITH_SM3.Equals(signScheme) ? CertificateEntry.ALGORITHM_TYPE_SM2 :
+ default!;
+ return !string.IsNullOrEmpty(algorithmType);
+ }
+
+ private static TRequest EnsureRequestWechatpaySerialNumberIsSetUseCertificateManager(ICertificateManager manager, string signScheme, TRequest request)
+ where TRequest : WechatTenpayRequest
+ {
+ if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
+ {
+ if (!TryGetAlgorithmType(signScheme, out string algorithmType))
+ throw new NotSupportedException($"Unsupported signing scheme: \"{signScheme}\".");
+
+ IEnumerable entries = manager.AllEntries();
+ entries = entries.Where(e => e.AlgorithmType == algorithmType).OrderByDescending(e => e.ExpireTime);
+ if (!entries.Any())
+ throw new Exception("The platform certificate manager is empty. Please make sure you have downloaded platform (NOT merchant) certificates first.");
+
+ CertificateEntry entry = entries.First();
+ request.WechatpaySerialNumber = entry.SerialNumber;
+ }
+
+ return request;
+ }
+
+ private static async Task EnsureRequestWechatpaySerialNumberIsSetUseCertificateManagerAsync(ICertificateManagerAsync manager, string signScheme, TRequest request, CancellationToken cancellationToken = default)
+ where TRequest : WechatTenpayRequest
+ {
+ if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
+ {
+ if (!TryGetAlgorithmType(signScheme, out string algorithmType))
+ throw new NotSupportedException($"Unsupported signing scheme: \"{signScheme}\".");
+
+ IEnumerable entries = await manager.AllEntriesAsync(cancellationToken).ConfigureAwait(false);
+ entries = entries.Where(e => e.AlgorithmType == algorithmType).OrderByDescending(e => e.ExpireTime);
+ if (!entries.Any())
+ throw new Exception("The platform certificate manager is empty. Please make sure you have downloaded platform (NOT merchant) certificates first.");
+
+ CertificateEntry entry = entries.First();
+ request.WechatpaySerialNumber = entry.SerialNumber;
+ }
+
+ return request;
+ }
+
+ private static TRequest EnsureRequestWechatpaySerialNumberIsSetUsePublicKeyManager(IPublicKeyManager manager, string signScheme, TRequest request)
+ where TRequest : WechatTenpayRequest
+ {
+ if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
+ {
+ if (!TryGetAlgorithmType(signScheme, out string algorithmType))
+ throw new NotSupportedException($"Unsupported signing scheme: \"{signScheme}\".");
+
+ IEnumerable entries = manager.AllEntries();
+ entries = entries.Where(e => e.AlgorithmType == algorithmType);
+ if (!entries.Any())
+ throw new Exception("The platform public key manager is empty. Perhaps you forget to add one?");
+
+ PublicKeyEntry entry = entries.First();
+ request.WechatpaySerialNumber = entry.SerialNumber;
+ }
+ return request;
+ }
+
+ private static async Task EnsureRequestWechatpaySerialNumberIsSetUsePublicKeyManagerAsync(IPublicKeyManagerAsync manager, string signScheme, TRequest request, CancellationToken cancellationToken = default)
+ where TRequest : WechatTenpayRequest
+ {
+ if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
+ {
+ if (!TryGetAlgorithmType(signScheme, out string algorithmType))
+ throw new NotSupportedException($"Unsupported signing scheme: \"{signScheme}\".");
+
+ IEnumerable entries = await manager.AllEntriesAsync(cancellationToken).ConfigureAwait(false);
+ entries = entries.Where(e => e.AlgorithmType == algorithmType);
+ if (!entries.Any())
+ throw new Exception("The platform public key manager is empty. Perhaps you forget to add one?");
+
+ PublicKeyEntry entry = entries.First();
+ request.WechatpaySerialNumber = entry.SerialNumber;
+ }
+ return request;
+ }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/[Internal]/WechatTenpayClientSigningExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/[Internal]/WechatTenpayClientSigningExtensions.cs
index 3f741c0f..0d381ca1 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/[Internal]/WechatTenpayClientSigningExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/[Internal]/WechatTenpayClientSigningExtensions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -10,75 +11,54 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
internal static class WechatTenpayClientSigningExtensions
{
- public static ErroredResult VerifySignature(this WechatTenpayClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber)
+ public static ErroredResult _VerifySignature(this WechatTenpayClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber)
{
if (client is null) throw new ArgumentNullException(nameof(client));
- switch (client.PlatformAuthScheme)
+ PlatformAuthScheme authSchema;
+ if (!TryGetAuthScheme(client, strSerialNumber, out authSchema))
+ {
+ return ErroredResult.Fail(new Exception("Could not detect the platform auth schema because the serial number is missing or invalid."));
+ }
+
+ switch (authSchema)
{
case PlatformAuthScheme.Certificate:
{
- CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(strSerialNumber);
- if (!entry.HasValue)
- {
- return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate matched the serial number \"{strSerialNumber}\"."));
- }
-
- return GenerateSignatureResultByCertificate(
- scheme: strSignScheme,
- certificate: entry.Value.Certificate,
- message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
- signature: strSignature
- );
+ return VerifySignatureUseCertificateManager(client.PlatformCertificateManager, strTimestamp: strTimestamp, strNonce: strNonce, strContent: strContent, strSignature: strSignature, strSignScheme: strSignScheme, strSerialNumber: strSerialNumber);
}
case PlatformAuthScheme.PublicKey:
{
- PublicKeyEntry? entry = client.PlatformPublicKeyManager.GetEntry(strSerialNumber);
- if (!entry.HasValue)
- {
- return ErroredResult.Fail(new Exception($"The platform public key manager does not contain a key matched the serial number \"{strSerialNumber}\"."));
- }
-
- return GenerateSignatureResultByPublicKey(
- scheme: strSignScheme,
- publicKey: entry.Value.PublicKey,
- message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
- signature: strSignature
- );
+ return VerifySignatureUsePublicKeyManager(client.PlatformPublicKeyManager, strTimestamp: strTimestamp, strNonce: strNonce, strContent: strContent, strSignature: strSignature, strSignScheme: strSignScheme, strSerialNumber: strSerialNumber);
}
default:
- return ErroredResult.Fail(new Exception($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\"."));
+ return ErroredResult.Fail(new NotSupportedException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\"."));
}
}
- public static async Task VerifySignatureAsync(this WechatTenpayClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber, CancellationToken cancellationToken = default)
+ public static async Task _VerifySignatureAsync(this WechatTenpayClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
- switch (client.PlatformAuthScheme)
+ PlatformAuthScheme authSchema;
+ if (!TryGetAuthScheme(client, strSerialNumber, out authSchema))
+ {
+ return ErroredResult.Fail(new Exception("Could not detect the platform auth schema because the serial number is missing or invalid."));
+ }
+
+ switch (authSchema)
{
case PlatformAuthScheme.Certificate:
{
if (client.PlatformCertificateManager is not ICertificateManagerAsync)
{
// 降级为同步调用
- return VerifySignature(client, strTimestamp, strNonce, strContent, strSignature, strSignScheme, strSerialNumber);
+ return _VerifySignature(client, strTimestamp, strNonce, strContent, strSignature, strSignScheme, strSerialNumber);
}
- CertificateEntry? entry = await ((ICertificateManagerAsync)client.PlatformCertificateManager).GetEntryAsync(strSerialNumber, cancellationToken).ConfigureAwait(false);
- if (!entry.HasValue)
- {
- return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate matched the serial number \"{strSerialNumber}\"."));
- }
-
- return GenerateSignatureResultByCertificate(
- scheme: strSignScheme,
- certificate: entry.Value.Certificate,
- message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
- signature: strSignature
- );
+ return await VerifySignatureUseCertificateManagerAsync((ICertificateManagerAsync)client.PlatformCertificateManager, strTimestamp: strTimestamp, strNonce: strNonce, strContent: strContent, strSignature: strSignature, strSignScheme: strSignScheme, strSerialNumber: strSerialNumber, cancellationToken).ConfigureAwait(false);
}
case PlatformAuthScheme.PublicKey:
@@ -86,34 +66,130 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
if (client.PlatformCertificateManager is not IPublicKeyManagerAsync)
{
// 降级为同步调用
- return VerifySignature(client, strTimestamp, strNonce, strContent, strSignature, strSignScheme, strSerialNumber);
+ return _VerifySignature(client, strTimestamp, strNonce, strContent, strSignature, strSignScheme, strSerialNumber);
}
- PublicKeyEntry? entry = await ((IPublicKeyManagerAsync)client.PlatformPublicKeyManager).GetEntryAsync(strSerialNumber, cancellationToken).ConfigureAwait(false);
- if (!entry.HasValue)
- {
- return ErroredResult.Fail(new Exception($"The platform public key manager does not contain a key matched the serial number \"{strSerialNumber}\"."));
- }
-
- return GenerateSignatureResultByPublicKey(
- scheme: strSignScheme,
- publicKey: entry.Value.PublicKey,
- message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
- signature: strSignature
- );
+ return await VerifySignatureUseCertificateManagerAsync((IPublicKeyManagerAsync)client.PlatformPublicKeyManager, strTimestamp: strTimestamp, strNonce: strNonce, strContent: strContent, strSignature: strSignature, strSignScheme: strSignScheme, strSerialNumber: strSerialNumber, cancellationToken).ConfigureAwait(false);
}
default:
- return ErroredResult.Fail(new Exception($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\"."));
+ return ErroredResult.Fail(new NotSupportedException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\"."));
}
}
+ private static ErroredResult VerifySignatureUseCertificateManager(ICertificateManager manager, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber)
+ {
+ if (manager is null)
+ {
+ return ErroredResult.Fail(new NullReferenceException("The platform certificate manager is not configured."));
+ }
+
+ CertificateEntry? entry = manager.GetEntry(strSerialNumber);
+ if (!entry.HasValue)
+ {
+ return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate matched the serial number \"{strSerialNumber}\"."));
+ }
+
+ return GenerateVerifyResultByCertificate(
+ scheme: strSignScheme,
+ certificate: entry.Value.Certificate,
+ message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
+ signature: strSignature
+ );
+ }
+
+ private static async Task VerifySignatureUseCertificateManagerAsync(ICertificateManagerAsync manager, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber, CancellationToken cancellationToken = default)
+ {
+ if (manager is null)
+ {
+ return ErroredResult.Fail(new NullReferenceException("The platform certificate manager is not configured."));
+ }
+
+ CertificateEntry? entry = await manager.GetEntryAsync(strSerialNumber, cancellationToken).ConfigureAwait(false);
+ if (!entry.HasValue)
+ {
+ return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate matched the serial number \"{strSerialNumber}\"."));
+ }
+
+ return GenerateVerifyResultByCertificate(
+ scheme: strSignScheme,
+ certificate: entry.Value.Certificate,
+ message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
+ signature: strSignature
+ );
+ }
+
+ private static ErroredResult VerifySignatureUsePublicKeyManager(IPublicKeyManager manager, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber)
+ {
+ if (manager is null)
+ {
+ return ErroredResult.Fail(new NullReferenceException("The platform public key manager is not configured."));
+ }
+
+ PublicKeyEntry? entry = manager.GetEntry(strSerialNumber);
+ if (!entry.HasValue)
+ {
+ return ErroredResult.Fail(new Exception($"The platform public key manager does not contain a key matched the serial number \"{strSerialNumber}\"."));
+ }
+
+ return GenerateVerifyResultByPublicKey(
+ scheme: strSignScheme,
+ publicKey: entry.Value.PublicKey,
+ message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
+ signature: strSignature
+ );
+ }
+
+ private static async Task VerifySignatureUseCertificateManagerAsync(IPublicKeyManagerAsync manager, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber, CancellationToken cancellationToken = default)
+ {
+ if (manager is null)
+ {
+ return ErroredResult.Fail(new NullReferenceException("The platform public key manager is not configured."));
+ }
+
+ PublicKeyEntry? entry = await manager.GetEntryAsync(strSerialNumber, cancellationToken).ConfigureAwait(false);
+ if (!entry.HasValue)
+ {
+ return ErroredResult.Fail(new Exception($"The platform public key manager does not contain a key matched the serial number \"{strSerialNumber}\"."));
+ }
+
+ return GenerateVerifyResultByPublicKey(
+ scheme: strSignScheme,
+ publicKey: entry.Value.PublicKey,
+ message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
+ signature: strSignature
+ );
+ }
+
+ private static bool TryGetAuthScheme(WechatTenpayClient client, string strSerialNumber, out PlatformAuthScheme authScheme)
+ {
+ authScheme = client.PlatformAuthScheme;
+ if (client.PlatformAuthFallbackSwitch)
+ {
+ if (string.IsNullOrEmpty(strSerialNumber))
+ {
+ return false;
+ }
+
+ if (Regex.IsMatch(strSerialNumber, "^PUB_KEY_ID_", RegexOptions.IgnoreCase))
+ {
+ authScheme = PlatformAuthScheme.PublicKey;
+ }
+ else if (Regex.IsMatch(strSerialNumber, "^[A-Za-z0-9]+$", RegexOptions.IgnoreCase))
+ {
+ authScheme = PlatformAuthScheme.Certificate;
+ }
+ }
+
+ return true;
+ }
+
private static string GenerateMessageForSignature(string timestamp, string nonce, string body)
{
return $"{timestamp}\n{nonce}\n{body}\n";
}
- private static ErroredResult GenerateSignatureResultByCertificate(string scheme, string certificate, string message, string signature)
+ private static ErroredResult GenerateVerifyResultByCertificate(string scheme, string certificate, string message, string signature)
{
string publicKey = string.Empty;
@@ -146,10 +222,10 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
break;
}
- return GenerateSignatureResultByPublicKey(scheme, publicKey, message, signature);
+ return GenerateVerifyResultByPublicKey(scheme, publicKey, message, signature);
}
- private static ErroredResult GenerateSignatureResultByPublicKey(string scheme, string publicKey, string message, string signature)
+ private static ErroredResult GenerateVerifyResultByPublicKey(string scheme, string publicKey, string message, string signature)
{
ErroredResult result;
@@ -199,7 +275,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
default:
{
- result = ErroredResult.Fail(new Exception($"Unsupported signing scheme: \"{scheme}\"."));
+ result = ErroredResult.Fail(new NotSupportedException($"Unsupported signing scheme: \"{scheme}\"."));
}
break;
}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Utilities/[Internal]/ReflectionHelper.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Utilities/[Internal]/ReflectionHelper.cs
index ad62769b..9d7ecd15 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Utilities/[Internal]/ReflectionHelper.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Utilities/[Internal]/ReflectionHelper.cs
@@ -10,7 +10,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
{
internal static partial class ReflectionHelper
{
- public static void ReplaceObjectStringProperties(object targetObj, ReplaceObjectStringPropertiesReplacementDelegate replacement)
+ public static void ReplaceObjectStringProperties(ref T targetObj, ReplaceObjectStringPropertiesReplacementDelegate replacement)
{
if (targetObj is null) throw new ArgumentNullException(nameof(targetObj));
if (replacement is null) throw new ArgumentNullException(nameof(replacement));
@@ -24,7 +24,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
{
public delegate (bool IsModified, string NewValue) ReplaceObjectStringPropertiesReplacementDelegate(object currentObj, PropertyInfo? currentProp, string oldValue);
- private static void InnerReplaceObjectStringProperties(ref object currentObj, PropertyInfo? currentProp, ReplaceObjectStringPropertiesReplacementDelegate replacement, ISet