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

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

Closed
slavap opened this issue Jun 1, 2024 · 2 comments · Fixed by #291
Closed

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

slavap opened this issue Jun 1, 2024 · 2 comments · Fixed by #291

Comments

@slavap
Copy link

slavap commented Jun 1, 2024

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 slavap changed the title HTMLIFrameElement contentWindow property in CORS case HTMLIFrameElement contentWindow property in CORS case - cannot use postMessage() Jun 4, 2024
@srujzs
Copy link
Contributor

srujzs commented Jun 5, 2024

I suspect this is the same issue as dart-lang/sdk#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.

@slavap
Copy link
Author

slavap commented Jun 6, 2024

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

srujzs added a commit to srujzs/web that referenced this issue Aug 24, 2024
Closes dart-lang/sdk#54443
Closes dart-lang#247
Closes dart-lang/sdk#54938

Since cross-origin objects have limitations around
access, wrappers are introduced to do the only safe
operations. Extension methods are added to get instances
of these wrappers.
@srujzs srujzs closed this as completed in 8501740 Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants