diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientEventExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientEventExtensions.cs index e2f9bbac..0067151d 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientEventExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientEventExtensions.cs @@ -4,6 +4,8 @@ using System.Xml.Linq; namespace SKIT.FlurlHttpClient.Wechat.Api { + using SKIT.FlurlHttpClient.Primitives; + /// /// 为 提供回调通知事件的扩展方法。 /// @@ -176,15 +178,31 @@ namespace SKIT.FlurlHttpClient.Wechat.Api /// 微信回调通知中的 "nonce" 查询参数。 /// 微信回调通知中的 "signature" 查询参数。 /// - public static bool VerifyEventSignatureForEcho(this WechatApiClient client, string webhookTimestamp, string webhookNonce, string webhookSignature) + public static ErroredResult VerifyEventSignatureForEcho(this WechatApiClient client, string webhookTimestamp, string webhookNonce, string webhookSignature) { if (client is null) throw new ArgumentNullException(nameof(client)); - List tmp = new List(capacity: 3) { client.Credentials.PushToken!, webhookTimestamp, webhookNonce }; - tmp.Sort(StringComparer.Ordinal); + ErroredResult result; - string sign = Utilities.SHA1Utility.Hash(string.Concat(tmp)).Value!; - return string.Equals(sign, webhookSignature, StringComparison.OrdinalIgnoreCase); + try + { + List tmp = new List(capacity: 3) { client.Credentials.PushToken!, webhookTimestamp, webhookNonce }; + tmp.Sort(StringComparer.Ordinal); + + string sign = Utilities.SHA1Utility.Hash(string.Concat(tmp)).Value!; + bool valid = string.Equals(sign, webhookSignature, StringComparison.OrdinalIgnoreCase); + + if (valid) + result = ErroredResult.Ok(); + else + result = ErroredResult.Fail(new Exception($"Signature does not match. Maybe \"{webhookSignature}\" is an illegal signature.")); + } + catch (Exception ex) + { + result = ErroredResult.Fail(ex); + } + + return result; } /// @@ -197,25 +215,34 @@ namespace SKIT.FlurlHttpClient.Wechat.Api /// 微信回调通知中请求正文(JSON 格式)。 /// 微信回调通知中的 "msg_signature" 查询参数。 /// - public static bool VerifyEventSignatureFromJson(this WechatApiClient client, string webhookTimestamp, string webhookNonce, string webhookJson, string webhookSignature) + public static ErroredResult VerifyEventSignatureFromJson(this WechatApiClient client, string webhookTimestamp, string webhookNonce, string webhookJson, string webhookSignature) { if (client is null) throw new ArgumentNullException(nameof(client)); + ErroredResult result; + try { - var encryptedEvent = client.JsonSerializer.Deserialize(webhookJson); - return Utilities.WxMsgCryptor.VerifySignature( + InnerEncryptedEvent encryptedEvent = client.JsonSerializer.Deserialize(webhookJson); + bool valid = Utilities.WxMsgCryptor.VerifySignature( sToken: client.Credentials.PushToken!, sTimestamp: webhookTimestamp, sNonce: webhookNonce, sMsgEncrypt: encryptedEvent.EncryptedData, sMsgSign: webhookSignature ); + + if (valid) + result = ErroredResult.Ok(); + else + result = ErroredResult.Fail(new Exception($"Signature does not match. Maybe \"{webhookSignature}\" is an illegal signature.")); } - catch + catch (Exception ex) { - return false; + result = ErroredResult.Fail(ex); } + + return result; } /// @@ -228,27 +255,36 @@ namespace SKIT.FlurlHttpClient.Wechat.Api /// 微信回调通知中请求正文(XML 格式)。 /// 微信回调通知中的 "msg_signature" 查询参数。 /// - public static bool VerifyEventSignatureFromXml(this WechatApiClient client, string webhookTimestamp, string webhookNonce, string webhookXml, string webhookSignature) + public static ErroredResult VerifyEventSignatureFromXml(this WechatApiClient client, string webhookTimestamp, string webhookNonce, string webhookXml, string webhookSignature) { if (client is null) throw new ArgumentNullException(nameof(client)); + ErroredResult result; + try { XDocument xDoc = XDocument.Parse(webhookXml); string? msgEncrypt = xDoc.Root?.Element("Encrypt")?.Value; - return Utilities.WxMsgCryptor.VerifySignature( + bool valid = Utilities.WxMsgCryptor.VerifySignature( sToken: client.Credentials.PushToken!, sTimestamp: webhookTimestamp, sNonce: webhookNonce, sMsgEncrypt: msgEncrypt!, sMsgSign: webhookSignature ); + + if (valid) + result = ErroredResult.Ok(); + else + result = ErroredResult.Fail(new Exception($"Signature does not match. Maybe \"{webhookSignature}\" is an illegal signature.")); } - catch + catch (Exception ex) { - return false; + result = ErroredResult.Fail(ex); } + + return result; } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.OpenAI/Extensions/WechatOpenAIClientEventExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.OpenAI/Extensions/WechatOpenAIClientEventExtensions.cs index 10ea60ef..f6f2c3aa 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.OpenAI/Extensions/WechatOpenAIClientEventExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.OpenAI/Extensions/WechatOpenAIClientEventExtensions.cs @@ -5,32 +5,8 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI /// /// 为 提供回调通知事件的扩展方法。 /// - public static class WechatOpenAIClientEventExtensions + public static partial class WechatOpenAIClientEventExtensions { - private static TEvent InnerDeserializeEventFromXml(this WechatOpenAIClient client, string webhookXml) - where TEvent : WechatOpenAIEvent - { - if (client is null) throw new ArgumentNullException(nameof(client)); - if (webhookXml is null) throw new ArgumentNullException(webhookXml); - - try - { - if (!Utilities.WxMsgCryptor.TryParseXml(webhookXml, out string? encryptedXml)) - throw new WechatOpenAIException("Failed to decrypt event data, because of the encrypted data is empty."); - - webhookXml = Utilities.WxMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.EncodingAESKey!, out _); - return Utilities.XmlHelper.Deserialize(webhookXml); - } - catch (WechatOpenAIException) - { - throw; - } - catch (Exception ex) - { - throw new WechatOpenAIException("Failed to deserialize event data. Please see the inner exception for more details.", ex); - } - } - /// /// 从 XML 反序列化得到 对象。 /// @@ -99,4 +75,31 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI return xml; } } + + partial class WechatOpenAIClientEventExtensions + { + private static TEvent InnerDeserializeEventFromXml(this WechatOpenAIClient client, string webhookXml) + where TEvent : WechatOpenAIEvent + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (webhookXml is null) throw new ArgumentNullException(webhookXml); + + try + { + if (!Utilities.WxMsgCryptor.TryParseXml(webhookXml, out string? encryptedXml)) + throw new WechatOpenAIException("Failed to decrypt event data, because of the encrypted data is empty."); + + webhookXml = Utilities.WxMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.EncodingAESKey!, out _); + return Utilities.XmlHelper.Deserialize(webhookXml); + } + catch (WechatOpenAIException) + { + throw; + } + catch (Exception ex) + { + throw new WechatOpenAIException("Failed to deserialize event data. Please see the inner exception for more details.", ex); + } + } + } }