Question

We are not able to call balanced.card.create from a Phonegap application. This is reproduced in a stock Phonegap application here: https://github.com/kevg/phonegap-balanced. Full details are in the README.md on github, but the basic summary is:

For those not familiar with phonegap, the main page that loads is index.html. This initializes phonegap in index.js. When the device is ready, we will show a hidden DIV with a button named "Execute Balanced." When you click this button, app.executeBalanced in index.js will be called which prompts for the balanced marketplace URI, loads balanced.js with $.getScript, and then calls balanced.card.create with a test credit card.

The expected result is that callbackHandler is called or an exception is caught. Instead, it seems the execution of the Javascript thread disappears into balanced.card.create, never to return and without any error.

example screenshot

Was it helpful?

Solution

Alrighty, I found the bug in balanced.js. So, in Phonegap, window.location.href returns something like file:///.../index.html. Balanced.js creates an iframe to something like https://js.balancedpayments.com/proxy#file

var src = proxy + "#" + encodeURIComponent(window.location.href);

https://github.com/balanced/balanced-js/blob/master/src/utils.js#L48

In the script returned in proxy.html (which I can't find on github), it does:

c.parentURL=decodeURIComponent(
    window.location.hash.replace(/^#/,"")
  ).replace(/#.*$/,"")
c.parentDomain=c.parentURL.replace(/([^:]+:\/\/[^\/]+).*/,"$1")

The regex doesn't match because file: has three slashes. Now, at first, I thought I could just convert the regex to:

/([^:]+:\/+[^\/]+).*/

However, then there's another problem, because balanced does a security origin check on the match:

if (d.origin.toLowerCase() !== c.toLowerCase()) return !1;

However, the regex returns file:///firstcomponent, whereas event.origin does not include a host name for the file scheme, so these won't match even with a fixed regex.

I can't change anything in the script returned in the proxy response because if I load that from a domain other than balancedpayments.com, then the AJAX POST fails (return code 0 with a blank body). Therefore, the only thing I can control is the hash passed to the iframe.

However, since this regex is a replace, we can simply pass exactly what we know we need (we don't care that the regex is a no-op).

Therefore, the solution is to change L48 above to:

var src = proxy + "#" + encodeURIComponent("file://");

This works.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top