Support new-win-policy with external sites (non-Node.js frame)

NWJS Version : 0.30.2
Operating System : Windows 10

Expected behavior

target="_blank" links clicked inside an external site (non-Node.js frame) should trigger the new-win-policy hook.

nw.Window.open('http://jsfiddle.net/kmdpjg4p/1/embedded/result/', {
    id: 'external-window'
  }, (win) => {
    win.on('new-win-policy', function (frame, url, policy) {
      console.log('externalWindow new-win-policy', frame, url, policy);
   });
})

Actual behavior

No new-win-policy event is fired

How to reproduce

  1. Inside the external window (jsFiddle), click the target="blank" link
  2. Notice how it spawns another NW.js window instead of opening in your default browser
  3. Noticed how the console.log('externalWindow new-win-policy', frame, url, policy); is never logged
<html>
<head>
  <title>nw-win-policy test</title>
</head>
<body>

<h1>index.html window</h1>

<a href="https://github.com/nwjs/nw.js">https://github.com/nwjs/nw.js</a>
<br />
<a href="https://github.com/nwjs/nw.js" target="_blank">blank https://github.com/nwjs/nw.js</a>

<iframe srcdoc="some iframe content<br /><a href='https://github.com/nwjs/nw.js'>https://github.com/nwjs/nw.js</a><br><a href='https://github.com/nwjs/nw.js' target='_blank'>blank https://github.com/nwjs/nw.js</a>"></iframe>

<script>
  console.log('index.html console log');

  // The `new-win-policy` hooks works because it spawns a node frame context
  nw.Window.get().on('new-win-policy', function (frame, url, policy) {
    console.log('nwWindow new-win-policy', frame, url, policy);
    nw.Shell.openExternal(url);
    policy.ignore();
  });

  /* * /
  // The `new-win-policy` hooks works because it spawns a node frame context
  nw.Window.open('other-window.html', {
    id: 'other-window'
  }, (win) => {
    win.on('new-win-policy', function (frame, url, policy) {
      console.log('otherWindow new-win-policy', frame, url, policy);
      nw.Shell.openExternal(url);
      policy.ignore();
    });
  });
  /* */

  // The `new-win-policy` will NOT work
  nw.Window.open('http://jsfiddle.net/kmdpjg4p/1/embedded/result/', {
    id: 'external-window'
  }, (win) => {
    win.on('new-win-policy', function (frame, url, policy) {
      console.log('externalWindow new-win-policy', frame, url, policy);
      nw.Shell.openExternal(url);
      policy.ignore();
    });
  });

</script>
</body>
</html>

Workaround

You can force all frames have a Node.js context by using the node-remote manifest option with a wildcard pattern. While we can trust the code we write, an XSS exploit in the app could lead to arbitrary code run in the host system for desktop users with Node.js enabled.

This seems to work even with the "nodejs": false manifest option but I need Node.js for the background and main window but want to disable unsafe Node.js for the external window/frame. There doesn’t seem to be a way to configure individually.

package.json (pattern is from #4787 (comment))

{
  // ...
  "node-remote": "*://*/*",
  // ...
}

Is there a workaround that doesn’t involve giving unsafe permissions to frames?

The workaround suggested here to inject some JavaScript in the page to hook any clicks on a <a target="_blank"> doesn’t work great for dynamic pages but could be adapted to look for any click that bubbles up to the root and then filter by element. It gets even more complicated with iframes in the website which Gitter has.


Update (2018-6-2): A pretty suitable and safe workaround is to open a NW.js frame that has a iframe with your external site embedded. Implemented here, https://gitlab.com/gitlab-org/gitter/desktop/merge_requests/210


Related issues

Created during investigation of https://gitlab.com/gitlab-org/gitter/desktop/issues/248

Author: Fantashit

1 thought on “Support new-win-policy with external sites (non-Node.js frame)

Comments are closed.