diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientEventVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientEventVerificationExtensions.cs index c476b5e3..627131e9 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientEventVerificationExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientEventVerificationExtensions.cs @@ -2,6 +2,8 @@ using System; namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness { + using SKIT.FlurlHttpClient.Primitives; + public static class WechatTenpayBusinessClientEventVerificationExtensions { /// @@ -11,84 +13,14 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// /// /// - public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string webhookAuthorization, string webhookBody) - { - return VerifyEventSignature(client, webhookAuthorization, webhookBody, out _); - } - - /// - /// 验证回调通知事件签名。 - /// - /// - /// - /// - /// - /// - public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string webhookAuthorization, string webhookBody, out Exception? error) + public static ErroredResult VerifyEventSignature(this WechatTenpayBusinessClient client, string webhookAuthorization, string webhookBody) { if (client is null) throw new ArgumentNullException(nameof(client)); - if (webhookAuthorization is null) throw new ArgumentNullException(nameof(webhookAuthorization)); - if (webhookBody is null) throw new ArgumentNullException(nameof(webhookBody)); - bool ret = WechatTenpayBusinessClientSigningExtensions.VerifySignature( + return WechatTenpayBusinessClientSigningExtensions.VerifySignature( client, strAuthorization: webhookAuthorization, - strContent: webhookBody, - out error - ); - - if (!ret) - error ??= new Exception($"Failed to verify webhook event. Maybe the raw signature is invalid."); - - return ret; - } - - /// - /// 验证回调通知事件签名。 - /// - /// - /// - /// 。 - /// - /// - /// - /// - public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSerialNumber) - { - return VerifyEventSignature( - client, - webhookTimestamp: webhookTimestamp, - webhookNonce: webhookNonce, - webhookBody: webhookBody, - webhookSignature: webhookSignature, - webhookSignatureAlgorithm: Constants.SignAlgorithms.SHA256_WITH_RSA, - webhookSerialNumber: webhookSerialNumber, - out _ - ); - } - - /// - /// 验证回调通知事件签名。 - /// - /// - /// - /// 。 - /// - /// - /// - /// - /// - public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSignatureAlgorithm, string webhookSerialNumber) - { - return VerifyEventSignature( - client, - webhookTimestamp: webhookTimestamp, - webhookNonce: webhookNonce, - webhookBody: webhookBody, - webhookSignature: webhookSignature, - webhookSignatureAlgorithm: webhookSignatureAlgorithm, - webhookSerialNumber: webhookSerialNumber, - out _ + strContent: webhookBody ); } @@ -101,55 +33,46 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// /// /// - /// /// - /// - public static bool VerifyEventSignature(this WechatTenpayBusinessClient 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, - webhookSignatureAlgorithm: Constants.SignAlgorithms.SHA256_WITH_RSA, - webhookSerialNumber: webhookSerialNumber, - out error - ); - } - - /// - /// 验证回调通知事件签名。 - /// - /// - /// - /// 。 - /// - /// - /// - /// - /// - /// - /// - public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSignatureAlgorithm, string webhookSerialNumber, out Exception? error) + public static ErroredResult VerifyEventSignature(this WechatTenpayBusinessClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSerialNumber) { if (client is null) throw new ArgumentNullException(nameof(client)); - bool ret = WechatTenpayBusinessClientSigningExtensions.VerifySignature( + return VerifyEventSignature( + client, + webhookTimestamp: webhookTimestamp, + webhookNonce: webhookNonce, + webhookBody: webhookBody, + webhookSignature: webhookSignature, + webhookSignatureAlgorithm: Constants.SignAlgorithms.SHA256_WITH_RSA, + webhookSerialNumber: webhookSerialNumber + ); + } + + /// + /// 验证回调通知事件签名。 + /// + /// + /// + /// 。 + /// + /// + /// + /// + /// + public static ErroredResult VerifyEventSignature(this WechatTenpayBusinessClient client, string webhookTimestamp, string webhookNonce, string webhookBody, string webhookSignature, string webhookSignatureAlgorithm, string webhookSerialNumber) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + + return WechatTenpayBusinessClientSigningExtensions.VerifySignature( client, strTimestamp: webhookTimestamp, strNonce: webhookNonce, strContent: webhookBody, strSignature: webhookSignature, strSignatureAlgorithm: webhookSignatureAlgorithm, - 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.TenpayBusiness/Extensions/WechatTenpayBusinessClientResponseVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientResponseVerificationExtensions.cs index 84e3aab7..6d84f871 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientResponseVerificationExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientResponseVerificationExtensions.cs @@ -3,6 +3,8 @@ using System.Text; namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness { + using SKIT.FlurlHttpClient.Primitives; + public static class WechatTenpayBusinessClientResponseVerificationExtensions { /// @@ -12,86 +14,15 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// /// /// - public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, TResponse response) - where TResponse : WechatTenpayBusinessResponse - { - return VerifyResponseSignature(client, response, out _); - } - - /// - /// 验证响应签名。 - /// - /// - /// - /// - /// - /// - public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, TResponse response, out Exception? error) + public static ErroredResult VerifyResponseSignature(this WechatTenpayBusinessClient client, TResponse response) where TResponse : WechatTenpayBusinessResponse { if (client is null) throw new ArgumentNullException(nameof(client)); - bool ret = WechatTenpayBusinessClientSigningExtensions.VerifySignature( + return WechatTenpayBusinessClientSigningExtensions.VerifySignature( client, strAuthorization: response.GetRawHeaders().GetFirstValueOrEmpty("TBEP-Authorization"), - strContent: Encoding.UTF8.GetString(response.GetRawBytes()), - out error - ); - - if (error is not null) - { - error = new WechatTenpayBusinessException("Verify signature of response failed. Please see the inner exception for more details.", error); - } - - return ret; - } - - /// - /// 验证响应签名。 - /// - /// - /// - /// 。 - /// - /// - /// - /// - public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber) - { - return VerifyResponseSignature( - client, - responseTimestamp: responseTimestamp, - responseNonce: responseNonce, - responseBody: responseBody, - responseSignature: responseSignature, - responseSignatureAlgorithm: Constants.SignAlgorithms.SHA256_WITH_RSA, - responseSerialNumber: responseSerialNumber, - out _ - ); - } - - /// - /// 验证响应签名。 - /// - /// - /// - /// 。 - /// - /// - /// - /// - /// - public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSignatureAlgorithm, string responseSerialNumber) - { - return VerifyResponseSignature( - client, - responseTimestamp: responseTimestamp, - responseNonce: responseNonce, - responseBody: responseBody, - responseSignature: responseSignature, - responseSignatureAlgorithm: responseSignatureAlgorithm, - responseSerialNumber: responseSerialNumber, - out _ + strContent: Encoding.UTF8.GetString(response.GetRawBytes()) ); } @@ -104,53 +35,46 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// /// /// - /// /// - public static bool VerifyResponseSignature(this WechatTenpayBusinessClient 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, - responseSignatureAlgorithm: Constants.SignAlgorithms.SHA256_WITH_RSA, - responseSerialNumber: responseSerialNumber, - out error - ); - } - - /// - /// 验证响应签名。 - /// - /// - /// - /// 。 - /// - /// - /// - /// - /// - /// - public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSignatureAlgorithm, string responseSerialNumber, out Exception? error) + public static ErroredResult VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber) { if (client is null) throw new ArgumentNullException(nameof(client)); - bool ret = WechatTenpayBusinessClientSigningExtensions.VerifySignature( + return VerifyResponseSignature( + client, + responseTimestamp: responseTimestamp, + responseNonce: responseNonce, + responseBody: responseBody, + responseSignature: responseSignature, + responseSignatureAlgorithm: Constants.SignAlgorithms.SHA256_WITH_RSA, + responseSerialNumber: responseSerialNumber + ); + } + + /// + /// 验证响应签名。 + /// + /// + /// + /// 。 + /// + /// + /// + /// + /// + public static ErroredResult VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSignatureAlgorithm, string responseSerialNumber) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + + return WechatTenpayBusinessClientSigningExtensions.VerifySignature( client, strTimestamp: responseTimestamp, strNonce: responseNonce, strContent: responseBody, strSignature: responseSignature, strSignatureAlgorithm: responseSignatureAlgorithm, - 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.TenpayBusiness/Extensions/__Internal/WechatTenpayBusinessClientSigningExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/__Internal/WechatTenpayBusinessClientSigningExtensions.cs index 715bbbc6..b4ab1a8d 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/__Internal/WechatTenpayBusinessClientSigningExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/__Internal/WechatTenpayBusinessClientSigningExtensions.cs @@ -8,90 +8,86 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness internal static class WechatTenpayBusinessClientSigningExtensions { - public static bool VerifySignature(this WechatTenpayBusinessClient client, string strAuthorization, string strContent, out Exception? error) + public static ErroredResult VerifySignature(this WechatTenpayBusinessClient client, string strAuthorization, string strContent) { - if (!string.IsNullOrEmpty(strAuthorization)) - { - try - { - IDictionary dictAuthorization = strAuthorization - .Split(',') - .Select(s => s.Trim().Split(new char[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries)) - .ToDictionary( - k => k[0], - v => v.Length > 1 ? v[1].TrimStart('\"').TrimEnd('\"') : null - ); - string strTimestamp = dictAuthorization.GetValueOrDefault("timestamp")!; - string strNonce = dictAuthorization.GetValueOrDefault("nonce")!; - string strSignature = dictAuthorization.GetValueOrDefault("signature")!; - string strSignAlgorithm = dictAuthorization.GetValueOrDefault("signature_algorithm")!; - string strSerialNumber = dictAuthorization.GetValueOrDefault("tbep_serial_number")!; + ErroredResult result; - return VerifySignature( - client, - strTimestamp: strTimestamp, - strNonce: strNonce, - strContent: strContent, - strSignature: strSignature, - strSignatureAlgorithm: strSignAlgorithm, - strSerialNumber: strSerialNumber, - out error + try + { + IDictionary dictAuthorization = strAuthorization + .Split(',') + .Select(s => s.Trim().Split(new char[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries)) + .ToDictionary( + k => k[0], + v => v.Length > 1 ? v[1].TrimStart('\"').TrimEnd('\"') : null ); - } - catch (Exception ex) - { - error = ex; - return false; - } + string strTimestamp = dictAuthorization.GetValueOrDefault("timestamp")!; + string strNonce = dictAuthorization.GetValueOrDefault("nonce")!; + string strSignature = dictAuthorization.GetValueOrDefault("signature")!; + string strSignAlgorithm = dictAuthorization.GetValueOrDefault("signature_algorithm")!; + string strSerialNumber = dictAuthorization.GetValueOrDefault("tbep_serial_number")!; + + result = VerifySignature( + client, + strTimestamp: strTimestamp, + strNonce: strNonce, + strContent: strContent, + strSignature: strSignature, + strSignatureAlgorithm: strSignAlgorithm, + strSerialNumber: strSerialNumber + ); + } + catch (Exception ex) + { + result = ErroredResult.Fail(ex); } - error = new Exception("The value of \"TBEP-Authorization\" is empty."); - return false; + return result; } - public static bool VerifySignature(this WechatTenpayBusinessClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignatureAlgorithm, string strSerialNumber, out Exception? error) + public static ErroredResult VerifySignature(this WechatTenpayBusinessClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignatureAlgorithm, string strSerialNumber) { if (client is null) throw new ArgumentNullException(nameof(client)); + ErroredResult result; + switch (strSignatureAlgorithm) { case Constants.SignAlgorithms.SHA256_WITH_RSA: { - if (client.Credentials.TBEPCertificateSerialNumber is not null && - client.Credentials.TBEPCertificatePublicKey is not null) + try { - try + if (!string.Equals(client.Credentials.TBEPCertificateSerialNumber, strSerialNumber)) { - if (!string.Equals(client.Credentials.TBEPCertificateSerialNumber, strSerialNumber)) - { - error = new Exception($"There is no TBEP public key matched the serial number \"{strSerialNumber}\"."); - return false; - } + result = ErroredResult.Fail(new Exception($"There is no TBEP public key matched the serial number \"{strSerialNumber}\".")); + break; + } - error = null; - return Utilities.RSAUtility.Verify( - publicKeyPem: client.Credentials.TBEPCertificatePublicKey, - message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent), - encodingSignature: new EncodedString(strSignature, EncodingKinds.Base64) - ); - } - catch (Exception ex) - { - error = ex; - return false; - } + bool valid = Utilities.RSAUtility.Verify( + publicKeyPem: client.Credentials.TBEPCertificatePublicKey, + 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) + { + result = ErroredResult.Fail(ex); } - - error = new Exception("There is no TBEP public key or serial number."); - return false; } + break; default: { - error = new Exception($"Unsupported sign algorithm: \"{strSignatureAlgorithm}\"."); - return false; + result = ErroredResult.Fail(new Exception($"Unsupported sign algorithm: \"{strSignatureAlgorithm}\".")); } + break; } + + return result; } private static string GenerateMessageForSignature(string timestamp, string nonce, string body)