web icon indicating copy to clipboard operation
web copied to clipboard

HTMLIFrameElement contentWindow property in CORS case - cannot use postMessage()

Open slavap opened this issue 1 year ago • 2 comments

I am trying to migrate from html package, and figured out that it is impossible to call postMessage() for iframe with content from another domain.

myIFrame.contentWindow?.postMessage('aaa'.toJS, '*'.toJS);

The same code with html package works without any security exceptions.

I'm getting the following error when accessing myIFrame.contentWindow: SecurityError: Failed to read a named property from 'Window': Blocked a frame with origin "http://localhost:51005" from accessing a cross-origin frame.

There is a quite ugly workaround for this issue.

Add to index.html:

<script>
    window.jsMyx = {
      postMessage(iframeElt, msg) {
        if (iframeElt) {
          iframeElt.contentWindow.postMessage(msg, '*');
        }
      }
    };
  </script>

Then in Dart:

import 'dart:js_interop';

import 'package:web/web.dart' as web;

extension type JsMyx._(JSObject _) implements JSObject {
  external void postMessage(web.HTMLIFrameElement iframe, JSAny? msg);
}

@JS()
external JsMyx get jsMyx;

And the following call works without any errors again:

void _sendMessage(Map<String, String> msg) {
    if (kIsWeb) {
      HTMLIFrameElement? fr = getMyIframe();
      if (fr != null) {
        jsMyx.postMessage(fr, msg.jsify());
      }
  }
}

slavap avatar Jun 01 '24 03:06 slavap

I suspect this is the same issue as https://github.com/dart-lang/sdk/issues/54443.

The general complication is that null-checks violate cross-origin policy as it's a toString call in JS. This is true for the JS compilers, whereas I believe dart2wasm likely avoids this issue due to how it does its null-checks and then immediately boxes. Using a conditional import could probably also work as a workaround if so.

Fixing this will likely involve a runtime type that dart2js/ddc knows not to call any members on, or providing some other interface that allows users to make cross-origin calls while avoiding null and type-checks in the JS compilers. dart:html does the latter.

srujzs avatar Jun 05 '24 16:06 srujzs

@srujzs Looks like the same problem in devtools was "solved" by disabling dart2js optimizations :-( Also trick with safelyPostMessage() extension is not working.

slavap avatar Jun 06 '24 05:06 slavap