Closed Bug 2066198 Opened 12 days ago Closed 5 days ago

Allow `resource:` documents to load module scripts from resource/chrome URLs without CORS checks

Categories

(Core :: DOM: Security, enhancement)

enhancement

Tracking

()

RESOLVED FIXED
157 Branch
Tracking Status
firefox157 --- fixed

People

(Reporter: calixte, Assigned: calixte)

References

(Blocks 1 open bug)

Details

Attachments

(1 file)

In order to be able to use some reusable components (with chrome://global origin) in the pdf viewer (with resource://pdf.jsorigin) we'd need to skip CORS.
For now, the only workaround is to duplicate some js & css code which is a pity and has to be maintained.

What is the component you want to import? I think we can help better the more detail you provide.

I wonder if we can expose the module via resource?
I hope Dan knows this better and can give more specific advice

Flags: needinfo?(dveditz)

For example, in order to fix bug 2057608, we'd like to be able to use:
https://searchfox.org/firefox-main/source/toolkit/content/widgets/moz-message-bar/moz-message-bar.mjs

but in the future, if it's possible, we'd like to use more reusable components.

I see the patch duplicating the widget, but I don't see a discussion of the problem this is working around. For example, in D319451 tgiles says "I think the moz-card can be used without having to deal with the CORS issue you mentioned" but I don't see a mention of a CORS issue in that differential or in that bug's comments. In D319454 there's "because of the CORS issue mentioned in the parent commit", meaning D319451 where I only found the previously mentioned response from tgiles but not the issue itself.

Where does CORS come in? given comment 2 I see other places use it as an import (where CORS is irrelevant) and as a <script type=module> where CORS would be relevant. But existing aboutPDFjs is already using other Chrome modules so I'm confused about that
https://searchfox.org/firefox-main/source/toolkit/components/aboutpdf/content/aboutPDF.html#17-20

All of our chrome:// URL content can be found using resource:// so that might work if they don't do "chrome things". For example
chrome://global/content/elements/moz-message-bar.mjs is also
resource://gre/chrome/toolkit/content/global/elements/moz-message-bar.mjs

unfortunately, right at the top the first two import use relative URLs, but the third is
import "chrome://global/content/elements/moz-button.mjs";

There's no need for that... it could just as easily be import "moz-button.mjs"; and then that should work. Of course then maybe moz-button has some non-relative urls that needs fixing, etc, but fixing it would improve their library as well as your use of it.

all of chrome://global might be contentaccessible, so maybe you don't need to fix that, as long as CORS is the only problem here.

Flags: needinfo?(dveditz) → needinfo?(cdenizet)

Sorry to not have been clear enough.

Right now we've in the viewer:
https://searchfox.org/firefox-main/source/toolkit/components/pdfjs/content/web/viewer.html#43

and the mentioned patch adds a component:
https://phabricator.services.mozilla.com/D319454#diff-change-3RBp9TCDWZ5x

So ideally I'd like to import moz-message-bar.mjs (in order to avoid the duplication) in pdfFeaturesNotification.mjs but then I hit a CORS issue.
I've exactly the same error when adding <script src="chrome://global/content/elements/moz-message-bar.mjs" type="module"></script> (the same with the resource:gre/chrome/...) in viewer.html, but if I remove type="module" the file is loaded (with a syntax error) but there's no CORS issue.

Flags: needinfo?(cdenizet)

Yes, type="module" definitely requires CORS. It's disappointing that the resource workaround didn't work. Clearly from your link you are able to use some modules from resource: URLs so I suspect we're running into the fact that URL.parse() is simpleminded and when it sees :// then whtever comes next must be an "origin", making resource://gre/ a different origin from resource://pdf.js/ and therefore needing CORS. Syntactically logical, but not that useful here. Maybe it made sense long ago when legacy web extensions could register resource: namespaces. I'm pretty sure web extensions can't do that anymore (except via the "experimental APIs" which are limited to Mozilla-made addons).

Your use-case makes sense, and doesn't seem dangerous. Some "allow PDF Viewer to..." exception isn't going to fly, so whatever we allow has to make sense and be safe more broadly. we could

a. change the CORS rules based on the target scheme. e.g. chrome: urls always say "yes" and we rely on the SecurityManager to prevent unwanted contexts from referencing chrome: urls

b. similar to 'a', but only do that if the triggering origin is also one of our internal schemes.

c. a targeted exception for just the module loading case. Need to make a decision whether it's a general pass when the target is an internal URL (rely on contentaccessible rules), or limit to resource: as the loading origin.

These widgets are already contentaccessible so any of the options that only care about the fact that the target is chrome: would effectively add our widgets to the "web platform". That's a bad outcome.... "only works in Firefox" sites, and then they break when we change how our widgets work. An exception just for modules is easier to reason about than a change to CORS itself so that's probably the best approach.

I don't want to grant a broad exception and say resource: documents don't need to use CORS at all regardless of the destination URL, even if narrowly limited to module loading. That's a chrome: privilege, and there's a reason when we use resource: instead of chrome:. But if the loading document is resource: and the destination is resource:, chrome:, or moz-src then it's reasonable to consider them same-origin ("Firefox") and allow module loading.

There might be lower-privilege chrome: or moz-src: documents that might need the same exception to load chrome: widgets so it sure would be nice to do something general based on protocol flags. That was the theory behind those, but sometimes people add new stuff with odd flags that might open up holes. I'd like to see if we could base this exception on both URLs being URI_IS_UI_RESOURCE. That would allow loading a few odd schemes that wouldn't make any sense as modules (page-icon:, moz-page-thumb:, moz-icon:, moz-newtab-wallpaper:), but I worry about what moz-newtab-remote-renderer: might allow.

Unfortunately, using URI_IS_UI_RESOURCE in just this way already burned us once (see bug 2041864 comment 6). We'll have to go with the uglier explicit list of trusted schemes. But handily, we have a helper function for just that purpose: nsContentSecurityUtils::IsTrustedScheme

Blocks: 2057608
Summary: Allow the built-in PDF viewer to skip CORS when loading chrome:// module scripts → Allow `resource:` documents to load module scripts from resource/chrome URLs without CORS checks

CORS checks on module loads block resource: documents from loading
cross-origin resource: modules or content-accessible chrome: modules.

Skip CORS when the triggering content principal uses resource: and
nsContentSecurityUtils::IsTrustedScheme accepts the target. Other URI checks
still apply, so moz-src: remains blocked.

Assignee: nobody → cdenizet
Status: NEW → ASSIGNED
Status: ASSIGNED → RESOLVED
Closed: 5 days ago
Resolution: --- → FIXED
Target Milestone: --- → 157 Branch
Depends on: 2069235
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: