From c631ece27460fda421eb9dd64a3581b088f4e94d Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Mon, 5 Feb 2024 15:58:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(tenpayv3):=20=E5=9F=BA=E4=BA=8E=20ErroredR?= =?UTF-8?q?esult=20=E6=94=B9=E9=80=A0=E9=AA=8C=E7=AD=BE=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...TenpayClientEventVerificationExtensions.cs | 71 ++------------ ...payClientResponseVerificationExtensions.cs | 94 ++---------------- .../WechatTenpayClientSigningExtensions.cs | 96 +++++++++---------- 3 files changed, 62 insertions(+), 199 deletions(-) diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs index 14959089..33c50579 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs @@ -2,6 +2,8 @@ using System; namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 { + using SKIT.FlurlHttpClient.Primitives; + public static class WechatTenpayClientEventVerificationExtensions { /// @@ -16,7 +18,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 /// 微信回调通知中的 "Wechatpay-Signature" 请求标头。 /// 微信回调通知中的 "Wechatpay-Serial" 请求标头。 /// - public static bool VerifyEventSignature(this WechatTenpayClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSerialNumber) + public static ErroredResult VerifyEventSignature(this WechatTenpayClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSerialNumber) { return VerifyEventSignature( client, @@ -42,80 +44,19 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 /// 微信回调通知中的 "Wechatpay-Signature-Type" 请求标头。 /// 微信回调通知中的 "Wechatpay-Serial" 请求标头。 /// - public static bool VerifyEventSignature(this WechatTenpayClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSignatureType, string webhookSerialNumber) - { - return VerifyEventSignature( - client, - webhookTimestamp: webhookTimestamp, - webhookNonce: webhookNonce, - webhookBody: webhookBody, - webhookSignature: webhookSignature, - webhookSignatureType: webhookSignatureType, - webhookSerialNumber: webhookSerialNumber, - out _ - ); - } - - /// - /// 验证回调通知事件签名。 - /// REF: https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-verification.html - /// REF: https://pay.weixin.qq.com/docs/partner/development/interface-rules/signature-verification.html - /// - /// - /// 微信回调通知中的 "Wechatpay-Timestamp" 请求标头。 - /// 微信回调通知中的 "Wechatpay-Nonce" 请求标头。 - /// 微信回调通知中请求正文。 - /// 微信回调通知中的 "Wechatpay-Signature" 请求标头。 - /// 微信回调通知中的 "Wechatpay-Serial" 请求标头。 - /// - /// - public static bool VerifyEventSignature(this WechatTenpayClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSerialNumber, out Exception? error) - { - return VerifyEventSignature( - client, - webhookTimestamp: webhookTimestamp, - webhookNonce: webhookNonce, - webhookBody: webhookBody, - webhookSignature: webhookSignature, - webhookSignatureType: Constants.SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256, - webhookSerialNumber: webhookSerialNumber, - out error - ); - } - - /// - /// 验证回调通知事件签名。 - /// REF: https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-verification.html - /// REF: https://pay.weixin.qq.com/docs/partner/development/interface-rules/signature-verification.html - /// - /// - /// 微信回调通知中的 "Wechatpay-Timestamp" 请求标头。 - /// 微信回调通知中的 "Wechatpay-Nonce" 请求标头。 - /// 微信回调通知中请求正文。 - /// 微信回调通知中的 "Wechatpay-Signature" 请求标头。 - /// 微信回调通知中的 "Wechatpay-Signature-Type" 请求标头。 - /// 微信回调通知中的 "Wechatpay-Serial" 请求标头。 - /// - /// - public static bool VerifyEventSignature(this WechatTenpayClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSignatureType, string webhookSerialNumber, out Exception? error) + public static ErroredResult VerifyEventSignature(this WechatTenpayClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSignatureType, string webhookSerialNumber) { if (client is null) throw new ArgumentNullException(nameof(client)); - bool ret = WechatTenpayClientSigningExtensions.VerifySignature( + return WechatTenpayClientSigningExtensions.VerifySignature( client, strTimestamp: webhookTimestamp, strNonce: webhookNonce, strContent: webhookBody, strSignature: webhookSignature, strSignScheme: webhookSignatureType, - strSerialNumber: webhookSerialNumber, - out error + strSerialNumber: webhookSerialNumber ); - - if (!ret) - error ??= new Exception($"Failed to verify webhook event. Maybe the raw signature \"{webhookSignature}\" is invalid."); - - return ret; } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs index f15bbdec..0faaa2d0 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs @@ -3,6 +3,8 @@ using System.Text; namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 { + using SKIT.FlurlHttpClient.Primitives; + public static class WechatTenpayClientResponseVerificationExtensions { /// @@ -14,23 +16,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 /// /// /// - public static bool VerifyResponseSignature(this WechatTenpayClient client, TResponse response) - where TResponse : WechatTenpayResponse - { - return VerifyResponseSignature(client, response, out _); - } - - /// - /// 验证响应签名。 - /// REF: https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-verification.html - /// REF: https://pay.weixin.qq.com/docs/partner/development/interface-rules/signature-verification.html - /// - /// - /// - /// - /// - /// - public static bool VerifyResponseSignature(this WechatTenpayClient client, TResponse response, out Exception? error) + public static ErroredResult VerifyResponseSignature(this WechatTenpayClient client, TResponse response) where TResponse : WechatTenpayResponse { if (client is null) throw new ArgumentNullException(nameof(client)); @@ -43,8 +29,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 responseBody: Encoding.UTF8.GetString(response.GetRawBytes()), responseSignature: response.WechatpaySignature, responseSignatureType: response.WechatpaySignatureType, - responseSerialNumber: response.WechatpayCertificateSerialNumber, - out error + responseSerialNumber: response.WechatpayCertificateSerialNumber ); } @@ -60,7 +45,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 /// /// /// - public static bool VerifyResponseSignature(this WechatTenpayClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber) + public static ErroredResult VerifyResponseSignature(this WechatTenpayClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber) { return VerifyResponseSignature( client, @@ -69,7 +54,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 responseBody: responseBody, responseSignature: responseSignature, responseSignatureType: Constants.SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256, - responseSerialNumber: responseSerialNumber + responseSerialNumber ); } @@ -86,80 +71,19 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 /// /// /// - public static bool VerifyResponseSignature(this WechatTenpayClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSignatureType, string responseSerialNumber) - { - return VerifyResponseSignature( - client, - responseTimestamp: responseTimestamp, - responseNonce: responseNonce, - responseBody: responseBody, - responseSignature: responseSignature, - responseSignatureType: responseSignatureType, - responseSerialNumber, - out _ - ); - } - - /// - /// 验证响应签名。 - /// REF: https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-verification.html - /// REF: https://pay.weixin.qq.com/docs/partner/development/interface-rules/signature-verification.html - /// - /// - /// - /// 。 - /// - /// - /// - /// - /// - public static bool VerifyResponseSignature(this WechatTenpayClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber, out Exception? error) - { - return VerifyResponseSignature( - client, - responseTimestamp: responseTimestamp, - responseNonce: responseNonce, - responseBody: responseBody, - responseSignature: responseSignature, - responseSignatureType: Constants.SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256, - responseSerialNumber, - out error - ); - } - - /// - /// 验证响应签名。 - /// REF: https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-verification.html - /// REF: https://pay.weixin.qq.com/docs/partner/development/interface-rules/signature-verification.html - /// - /// - /// - /// 。 - /// - /// - /// - /// - /// - /// - public static bool VerifyResponseSignature(this WechatTenpayClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSignatureType, string responseSerialNumber, out Exception? error) + public static ErroredResult VerifyResponseSignature(this WechatTenpayClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSignatureType, string responseSerialNumber) { if (client is null) throw new ArgumentNullException(nameof(client)); - bool ret = WechatTenpayClientSigningExtensions.VerifySignature( + return WechatTenpayClientSigningExtensions.VerifySignature( client, strTimestamp: responseTimestamp, strNonce: responseNonce, strContent: responseBody, strSignature: responseSignature, strSignScheme: responseSignatureType, - strSerialNumber: responseSerialNumber, - out error + strSerialNumber: responseSerialNumber ); - - if (!ret) - error ??= new Exception($"Failed to verify response. Maybe the raw signature \"{responseSignature}\" is invalid."); - - return ret; } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/__Internal/WechatTenpayClientSigningExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/__Internal/WechatTenpayClientSigningExtensions.cs index 387329fa..2b2973ed 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/__Internal/WechatTenpayClientSigningExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/__Internal/WechatTenpayClientSigningExtensions.cs @@ -7,92 +7,90 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 internal static class WechatTenpayClientSigningExtensions { - public static bool VerifySignature(this WechatTenpayClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber, out Exception? error) + 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)); + ErroredResult result; + switch (strSignScheme) { case Constants.SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256: { - if (client.PlatformCertificateManager is null) - { - error = new Exception("The platform certificate manager is not initialized."); - return false; - } - - CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(strSerialNumber); - if (!entry.HasValue) - { - error = new Exception($"The platform certificate manager does not contain a certificate with serial number \"{strSerialNumber}\"."); - return false; - } - - if (!CertificateEntry.ALGORITHM_TYPE_RSA.Equals(entry.Value.AlgorithmType)) - { - error = new Exception($"The platform certificate with serial number \"{strSerialNumber}\" is not for RSA."); - return false; - } - - error = null; try { - return Utilities.RSAUtility.VerifyByCertificate( + if (client.PlatformCertificateManager is null) + { + result = ErroredResult.Fail(new Exception("The platform certificate manager is not initialized.")); + break; + } + + CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(strSerialNumber); + if (!entry.HasValue) + { + result = ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate with serial number \"{strSerialNumber}\".")); + break; + } + + bool valid = Utilities.RSAUtility.VerifyByCertificate( certificatePem: entry.Value.Certificate, message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent), encodingSignature: new EncodedString(strSignature, EncodingKinds.Base64) ); + if (valid) + result = ErroredResult.Ok(); + else + result = ErroredResult.Fail(new Exception($"Signature does not match. Maybe \"{strSignature}\" is an illegal signature.")); } catch (Exception ex) { - error = ex; - return false; + result = ErroredResult.Fail(ex); } } + break; case Constants.SignSchemes.WECHATPAY2_SM2_WITH_SM3: { - if (client.PlatformCertificateManager is null) - { - error = new Exception("The platform certificate manager is not initialized."); - return false; - } - - CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(strSerialNumber); - if (!entry.HasValue) - { - error = new Exception($"The platform certificate manager does not contain a certificate with serial number \"{strSerialNumber}\"."); - return false; - } - - if (!CertificateEntry.ALGORITHM_TYPE_SM2.Equals(entry.Value.AlgorithmType)) - { - error = new Exception($"The platform certificate with serial number \"{strSerialNumber}\" is not for SM2."); - return false; - } - - error = null; try { - return Utilities.SM2Utility.VerifyWithSM3ByCertificate( + if (client.PlatformCertificateManager is null) + { + result = ErroredResult.Fail(new Exception("The platform certificate manager is not initialized.")); + break; + } + + CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(strSerialNumber); + if (!entry.HasValue) + { + result = ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate with serial number \"{strSerialNumber}\".")); + break; + } + + bool valid = Utilities.SM2Utility.VerifyWithSM3ByCertificate( certificatePem: entry.Value.Certificate, message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent), encodingSignature: new EncodedString(strSignature, EncodingKinds.Base64) ); + if (valid) + result = ErroredResult.Ok(); + else + result = ErroredResult.Fail(new Exception($"Signature does not match. Maybe \"{strSignature}\" is an illegal signature.")); } catch (Exception ex) { - error = ex; - return false; + result = ErroredResult.Fail(ex); } } + break; default: { - error = new Exception($"Unsupported signing scheme: \"{strSignScheme}\"."); - return false; + result = ErroredResult.Fail(new Exception($"Unsupported signing scheme: \"{strSignScheme}\".")); } + break; } + + return result; } private static string GenerateMessageForSignature(string timestamp, string nonce, string body)