Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

postMessage example from documentation doesn't work #420

Closed
FarhadG opened this issue Feb 11, 2019 · 10 comments
Closed

postMessage example from documentation doesn't work #420

FarhadG opened this issue Feb 11, 2019 · 10 comments

Comments

@FarhadG
Copy link

FarhadG commented Feb 11, 2019

I need the ability to be able for an inappbrowser instance to communicate with the parent (the opener). Given that there is no opener object with the inappbrowser, I've looked through repo's documentation and tests, and I cannot reproduce the postMessage API to communicate between an inappbrowser instance and the main Cordova application (parent).

Here's a simple example taken from the documentation/test within this repo:

const ref = cordova.InAppBrowser.open('http://www.google.com', '_blank');

ref.addEventListener('loadstop', () => {
  console.log('loadstop has been fired'); // this fires
  
  // when this has been executed, `webkit` variable doesn't exist inside of the `inappbrowser`
  // instance
  ref.executeScript({
    code: `(() => {
      var message = "TESTING!!!";
      webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify(message));
    })()`
  });
});

// this is never fired
ref.addEventListener('message', (...args) => {
  console.log('MESSAGE RECEIVED FROM IN_APP_BROWSER', ...args);
});
@dpa99c
Copy link
Contributor

dpa99c commented Feb 11, 2019

Did you install the plugin from the master branch (version 3.1.0-dev)?
The postMessage API functionality is currently not in the most recent release to npm (version 3.0.0).

@FarhadG
Copy link
Author

FarhadG commented Feb 11, 2019

@dpa99c I got this to work with the following: I had to always use an object and JSON.stringify that object, because just passing in a string didn't work.

@FarhadG
Copy link
Author

FarhadG commented Feb 11, 2019

That being said, do we have an idea of when this feature will become part of the release? Also, given that it's so easy to execute scripts inside of inappbrowser and now be able to retrieve data in the parent context, what are the security concerns? Given a hacker could maliciously inject code into our application (e.g. XSS), they would be able to take advantage of this plugin's functionality?

@dpa99c
Copy link
Contributor

dpa99c commented Feb 11, 2019

@dpa99c I got this to work with the following: I had to always use an object and JSON.stringify that object, because just passing in a string didn't work.

As illustrated in the documented example, the input must always be a stringified object: see here for reasons why.

@dpa99c
Copy link
Contributor

dpa99c commented Feb 11, 2019

That being said, do we have an idea of when this feature will become part of the release?

Above my pay grade 😄

Also, given that it's so easy to execute scripts inside of inappbrowser and now be able to retrieve data in the parent context, what are the security concerns? Given a hacker could maliciously inject code into our application (e.g. XSS), they would be able to take advantage of this plugin's functionality?

A hacker could indeed inject code into a page to trigger the postMessage API, so your implementation which handles the message event should be coded defensively so as to treat the message content as untrusted and sanitise as appropriate.
For example, you could use executeScript() to have your app inject a validation key into the webpage and have postMessage API send that key back in its event data.

@FarhadG
Copy link
Author

FarhadG commented Feb 11, 2019

That makes sense, @dpa99c, but I'm curious about the situation where a hacker could simply execute JS in a different site using this plugin. I know this is a bit broader than your PR but curious how to protect ourselves from this situation:

  • Execute JS in a different site (e.g. bank site)
  • Read/watch contents of the inappbrowser (e.g. click jacking)

@dpa99c
Copy link
Contributor

dpa99c commented Feb 11, 2019

Since these things don't directly relate to postMessage API, and since they are questions rather than issues, it may be better to ask/discuss on Cordova Slack channels than here.

@FarhadG
Copy link
Author

FarhadG commented Feb 11, 2019

Thanks for the quick responses, @dpa99c! Already using your code

@FarhadG FarhadG closed this as completed Feb 11, 2019
@Leonavas
Copy link

Leonavas commented Mar 2, 2019

@FarhadG Im facing the exact same situation, but even switching to the master branch (3.1.0-dev) as @dpa99c mentioned, the "message" listener is never fired. Are there any extra steps you had to take to make this work?

EDIT: Managed to make it work. If anyone gets stuck with this, the solution is to make something like this on the child page:
window['webkit'].messageHandlers['cordova_iab'].postMessage(JSON.stringify({'data': 'value'}))

@Skyedra
Copy link

Skyedra commented Sep 14, 2023

window['webkit'].messageHandlers['cordova_iab'].postMessage(JSON.stringify({'data': 'value'}))

The above solution will work on some devices (including my local one), however, I found it failed on some devices like Pixel 4, Galaxy S7, Pixel 3, Z Fold 4, etc.

TypeError: Cannot read properties of undefined (reading 'messageHandlers')

This solution (with slight modification inspired by Leonavas strategy) appears to be more reliable (and also doesn't throw an error in typescript):

const target = window['cordova_iab'] ?? window['webkit'].messageHandlers['cordova_iab'];
target.postMessage(JSON.stringify({'command': command}));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants