From the Moralis Streams API (i.e. an incoming webhook request), how do I verify the x-signature header? The docs say its just a sha3 of the body + api key, however this does not seem to work correctly. Here is what I've got so far. (part of one of my API controllers)
var signature = Request.Headers["x-signature"].FirstOrDefault(); if (signature.IsNullOrEmpty()) { logger.LogInformation("No signature was present from webhook request, ignoring."); return Ok(); } Request.EnableBuffering(); // Required to allow multiple reads // Read body again to a string using var reader = new StreamReader( Request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true ); var rawBody = await reader.ReadToEndAsync(); Request.Body.Position = 0; // Hash body using var hashMemStream = new MemoryStream(); var hashMemWriter = new StreamWriter(hashMemStream); await hashMemWriter.WriteAsync(rawBody + "<streams secret here>"); await hashMemWriter.FlushAsync(); hashMemStream.Position = 0; var hash = await SHA3_256.HashDataAsync(hashMemStream); var hashString = BytesToHex(hash); Request.Body.Position = 0; if (signature != hashString) { logger.LogInformation("Signature was incorrect from webhook, ignoring"); return Ok(); } The BytesToHex(string) method is implemented as:
private static string BytesToHex(byte[] bytes) { var sb = new StringBuilder("0x"); foreach (var b in bytes) sb.Append($"{b:x2}"); return sb.ToString(); } The x-signature is the same length as what I end up with but they are not the same.
I was able to snuff out from the official JS SDK that its calculated in their SDK as:
const generatedSignature = sha3(JSON.stringify(body) + secret); (taken from https://github.com/MoralisWeb3/Moralis-JS-SDK/blob/main/packages/streams/src/methods/verifySignature.ts#L12)
It seems very odd to re-serialize the body to a JS-specific implementation to then hash. Is there a reason for this?
Whats the recommended approach to this?