using System; using System.Web; using System.Text; using System.Net; using System.Threading.Tasks; using System.IO; using System.Linq; using Newtonsoft.Json; using System.Security.Cryptography; namespace Sample.ReceiveCallback { public class ReceiveCallbackHandler : HttpTaskAsyncHandler { // callback data as received from PayWiser private class Callback { public string Type { get; set; } public string Data { get; set; } public string HMAC { get; set; } } // inner callback data for pos payment as received from PayWiser private class POSPaymentCallback { public string PGReferenceID { get; set; } public string CustomerReferenceID { get; set; } public int TransactionType { get; set; } public int PaymentStatus { get; set; } public string PaymentDescription { get; set; } public string CardScheme { get; set; } public string CardType { get; set; } public string TerminalID { get; set; } public string TerminalIP { get; set; } public string TerminalPort { get; set; } } // inner callback data for pos refund as received from PayWiser (same structure as payment) private class POSRefundCallback: POSPaymentCallback { } public override bool IsReusable { get { return false; } } // main processing code public override async Task ProcessRequestAsync(HttpContext context) { // reject Get etc calls if (HttpContext.Current.Request.HttpMethod != "POST") { context.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed; //405 context.Response.SuppressContent = true; context.Response.TrySkipIisCustomErrors = true; return; } // reject if running on HTTP instead of HTTPS if (!HttpContext.Current.Request.IsSecureConnection) { context.Response.StatusCode = (int)HttpStatusCode.HttpVersionNotSupported; //505 context.Response.SuppressContent = true; context.Response.TrySkipIisCustomErrors = true; return; } try { // your own confirmation string, as entered into PayWiser PaymentGateway Dashboard for your account string confirmationString = "1234qwertz"; // allow only calls from this IP string allowedIP = "192.168.1.1"; // get POST data string postData = ReadParameters(context.Request.InputStream); // get sender (caller) IP string senderIP = GetClientIP(HttpContext.Current.Request); // reject calls from wrong IPs if (!senderIP.Equals(allowedIP)) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; //404 context.Response.SuppressContent = true; context.Response.TrySkipIisCustomErrors = true; return; } // deserialize data Callback callback = JsonConvert.DeserializeObject(postData); // calculate HMAC string calculatedHMAC = CalculateHMAC(callback.Data, confirmationString); // reject calls with wrong HMAC if (!calculatedHMAC.Equals(callback.HMAC)) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; //404 context.Response.SuppressContent = true; context.Response.TrySkipIisCustomErrors = true; return; } // deserialize inner callback data if (callback.Type.Equals("pos_payment")) { POSPaymentCallback posPayment = JsonConvert.DeserializeObject(callback.Data); // your own logic goes here } else if (callback.Type.Equals("pos_refund")) { POSRefundCallback posRefund = JsonConvert.DeserializeObject(callback.Data); // your own logic goes here } // successfully received context.Response.StatusCode = (int)HttpStatusCode.OK; //200 return; } catch { // PayWiser will retry sending context.Response.StatusCode = (int)HttpStatusCode.BadRequest; //400 return; } } private string ReadParameters(Stream streamParameters) { string ret = ""; try { using (StreamReader reader = new StreamReader(streamParameters)) ret = reader.ReadToEnd(); } catch { } return ret; } private string GetClientIP(HttpRequest httpRequest) { // in case of load balancers etc string ip = httpRequest.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (String.IsNullOrWhiteSpace(ip)) ip = httpRequest.ServerVariables["REMOTE_ADDR"]; else ip = ip.Split(',').Last().Trim(); return ip; } static private string CalculateHMAC(string payload, string confirmationSequence) { if (String.IsNullOrWhiteSpace(payload) || String.IsNullOrWhiteSpace(confirmationSequence)) return ""; var data = Encoding.UTF8.GetBytes(payload); var key = Encoding.UTF8.GetBytes(confirmationSequence); // Create HMAC-MD5 Algorithm; var hmac = new HMACMD5(key); // Compute hash. var hashBytes = hmac.ComputeHash(data); // Convert to HEX string. return System.BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); } } }