Search code examples
javascriptcallbackfrontendjsonp

How to trigger function based on API call and callback in 3rd party app


I am trying to listen for a javascript callback from a 3rd party app on my site. The app is minified so it is quite hard to reverse engineer. However, having used the Chrome debugger, the callback I want to capture is below, is there any way, I can trigger a function when that 'CollectEvent' callback is fired, with access to the 'email' variable? You can see in the console, that the callbacks are being created on the window, although of course they are named differently each time the code runs.

Recognising that I cannot edit that code directly as it is part of a 3rd party library.

!function() {
    var _0x14bdc8 = {
        'CollectEvent': function(_0x4a9e64, _0x3ac5b7) {
            if (_0x4a9e64) {
                _0x14bdc8[_0x304d('0xa7')] && (_0x30053a('COUPON_CODE_COOKIE_NAME', _0x4a9e64[_0x304d('0xd7')], 0x1),
                _0x14bdc8[_0x304d('0x6a')]());
                var _0x562cf7 = {
                    'shopId': _0x14bdc8[_0x304d('0xc2')],
                    'campaignId': _0x14bdc8[_0x304d('0x79')],
                    'email': encodeURIComponent(_0x4a9e64[_0x304d('0x23')]),
                    'code': _0x4a9e64['code'],
                    'customFields': encodeURIComponent(JSON[_0x304d('0x3')](_0x3ac5b7)),
                    'domain': window[_0x304d('0x73')][_0x304d('0x4a')],
                    'currentUrl': window[_0x304d('0x73')][_0x304d('0x6b')]
                };
                _0x14bdc8[_0x304d('0xa0')](_0x986b46 + '/api/wheelioapp/collectemail', _0x562cf7, function(_0xea4ea9) {
                    _0xea4ea9[_0x304d('0x89')] && _0x14bdc8[_0x304d('0x8f')](!0x1, !0x1, !0x0, !0x1);
                });
            } else
                alert(_0x304d('0x80'));
        },
    ...
    }
}

You can see here the Wheelio app object in the console and the callbacks which have been created (although they have different names each session).

enter image description here


Solution

  • I just need to log it

    Well, ok. We can't change functions created on-the-fly, but we can change other window functions.

    For example we can use encodeURIComponent. See this line:

    'email': encodeURIComponent(_0x4a9e64[_0x304d('0x23')]),
    

    It means that somehow the email will go into the encodeURIComponent. Good, because we can read it there:

    /* At the beginning */
    // This is helper function, detects correct email:
    function validateEmail(email) {
        const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        return re.test(String(email).toLowerCase());
    }
    // Keep old function
    let oldEncodeURIComponent = window.encodeURIComponent;
    // Crete new one
    window.encodeURIComponent = (data) => {
      if (validateEmail(data)) {
        // Gotcha!
        console.log('[encodeURIComponent]', data);
      }
      return oldEncodeURIComponent(data);
    }
    
    /* Here program works as normal, but creates lots of logs... */
    
    /* In the end */
    // If we can understand when we need to stop looking for email,
    //   we will disconnect our function:
    window.encodeURIComponent = oldEncodeURIComponent;
    

    So the idea is to read all data passing thru encodeURIComponent.

    P.S. Email validator is here