using System;
using System.Text;
using System.Text.Json;
using System.Collections.Generic;
using System.Security.Cryptography;
public static VerifyResult VerifySignature(
string method,
string bodyJson,
Dictionary<string, string> headers,
string apiKey,
Dictionary<string, string> queryParams
) {
if (!headers.TryGetValue("x-signature", out var signature) ||
!headers.TryGetValue("x-timestamp", out var tsStr) ||
!long.TryParse(tsStr, out var timestamp)) {
return new VerifyResult { Success = false, Cause = "missing or invalid headers" };
}
if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - timestamp) > 10000) {
return new VerifyResult { Success = false, Cause = "timestamp expired" };
}
var payload = method.Equals("GET", StringComparison.OrdinalIgnoreCase)
? JsonSerializer.Serialize(queryParams ?? new Dictionary<string, string>())
: (string.IsNullOrEmpty(bodyJson) ? "{}" : bodyJson);
var raw = $"{method.ToUpper()}|{timestamp}|{payload}";
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(apiKey));
var expected = Convert.ToHexString(hmac.ComputeHash(Encoding.UTF8.GetBytes(raw))).ToLower();
return signature == expected
? new VerifyResult { Success = true }
: new VerifyResult { Success = false, Cause = "verify failed" };
}
import time, hmac, hashlib, json
def verify_signature(method, body_json, headers, api_key, query_params=None):
sig = headers.get("x-signature")
ts_str = headers.get("x-timestamp")
try:
timestamp = int(ts_str)
except (ValueError, TypeError):
return { "success": False, "cause": "missing or invalid headers" }
if not sig or abs(int(time.time() * 1000) - timestamp) > 10000:
return { "success": False, "cause": "timestamp expired" }
if method.upper() == "GET":
payload = json.dumps(query_params or {}, separators=(",", ":"))
else:
payload = body_json or "{}"
raw = f"{method.upper()}|{timestamp}|{payload}"
expected = hmac.new(api_key.encode(), raw.encode(), hashlib.sha256).hexdigest()
return { "success": sig == expected, "cause": None if sig == expected else "verify failed" }