Reply
Member
Posts: 9
Registered: ‎12-17-2020

Accept Hosted onReceiveCommunications function causes error on specific response

[ Edited ]

I tested a hundred times and everything worked, then went live and my very first customer encountered an error that my team could not replicate - until we dug deep into what was happening.

 

The onReceiveCommunication function, as listed on the API Accept Hosted how-to's page calls for this following:

 

 

AuthorizeNetPopup.onReceiveCommunication = function (querystr) {
	var params = parseQueryString(querystr);
	switch (params["action"]) {
		case "successfulSave":
			AuthorizeNetPopup.closePopup();
			break;
		case "cancel":
			AuthorizeNetPopup.closePopup();
			break;
		case "transactResponse":
			var response = params["response"];
			document.getElementById("token").value = response;
			AuthorizeNetPopup.closePopup();
// pass response to backend to record transaction
var res = JSON.parse(params["response"]) ; // THIS BREAKS because "response" is not a proper json string due below issue
httpReceipt(res) ; // pass JSON to backend to record transaction in DB break; case "resizeWindow": var w = parseInt(params["width"]); var h = parseInt(params["height"]); var ifrm = document.getElementById("iframeAuthorizeNet"); ifrm.style.width = w.toString() + "px"; ifrm.style.height = h.toString() + "px"; centerPopup(); break; } function parseQueryString(str) { var vars = []; var arr = str.split('&'); var pair; for (var i = 0; i < arr.length; i++) { pair = arr[i].split('='); vars.push(pair[0]); vars[pair[0]] = unescape(pair[1]); } return vars; }
 

 

 

 

However, the call to `parseQueryString` errors out IF any of the data being sent back (from Authorize) contains an ampersand (&) back in the "response" parameter.  

 

This is happening specifically because Authroize's response is both a standard URL with one of the parameter values being a JSON string.  IE: action=transactResponse&response={ JSON string here }

 

If any value in the JSON string has a "&" in it, then the parseQueryString function will split the JSON string in two.  It so happens that my clients company name is "Blah Bar & Grill" - and Authorize was sending back the response as:  

 

 

action=transactResponse&response={ ....{ .... "company" : "Blah Bar & Grill", "address": "123 Main Street" .... }, .....}


Which would then be split into the following parameters into the array "vars" as:
[ 
     [ "action" : "transactResponse"],
     [ "response" : "{ ....{ .... "company" : "Blah Bar " ]
     [ " Grill", "address": "123 Main Street" .... }, .....} ]
]

 

So, anyone trying to use the full "response" value - and convert it back to a proper JSON, it would fail:   var res = JSON.parse(params["response"] ;  because after splitting on the "&", params{[response'] was not a proper json string anymore.

 

Thus any "&" inside the JSON string would be split further and further.  Authorize needs to send a fully encoded URI/URIComponent repsonse back OR send back a proper JSON.  But mixing the json string into a URL type response is bad form that leads to this kind of problem.

 

To fix the issue, I had to rewrite the above Authorize.net provided functions to the following - its not the best, or cleanest, but at the moment it seems to do the trick.  It also accounts for additional URL params specificed after the "response={JSON string}" if they were ever to exist:

 

 

    AuthorizeNetPopup.onReceiveCommunication = function (str) {
      var params = parseResponse(str) ;
      switch (params.action) {
        case "successfulSave":
          AuthorizeNetPopup.closePopup();
          break;
        case "cancel":
          AuthorizeNetPopup.closePopup();
          break;
        case "transactResponse":
          httpReceipt(params.response) ;  // my code to send the JSON to my backend to record the transaction data into my DB.
          AuthorizeNetPopup.closePopup();
          break;
        case "resizeWindow":
          var w = parseInt(params.width) ;
          var h = parseInt(params.height) ;
          var ifrm = document.getElementById("iframeAuthorizeNet");
          ifrm.style.width = w.toString() + "px";
          ifrm.style.height = h.toString() + "px";
          centerPopup();
          break;
      }
    };

      function parseResponse(str) {
        var resInfo = [], res = {} ;
        if (str.match("&response=")) {
          var params = str.split("&response=") ; // leading params & response obj
          if (params[1].match("}&")) {
            resInfo = params[1].split("}&") ;  // splits off anything at end of obj
            res.response = JSON.parse(resInfo[0] + "}") ;  // add } to complete obj string again
          } else {
            res.response = JSON.parse(params[1]) ;
          }
          if (resInfo[1]) {
            params = params[0]+ "&" +resInfo[1] ;  // join url params back together  
          } else {
            params = params[0] ;
          }
        }  else {
          params = str ;
        }
        params = new URLSearchParams(encodeURI(params)) ;  //encode then parse
        params.forEach(function(value, key) {
          res[key] = value ;
        }) ;

        return res ;
      } 

 

I bring this to everyones attention because both of the original functions come straight from Authorize.nets API Accept Hosted page documentation.  It means Authorize.nets own functions, can't handle Authorize.nets own transaction response if the there is an additional "&" anywhere inside the "response={ JSON STRING}" paraemter.