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

request: allow to retrieve a tabId and documentId from the content script #469

Open
fregante opened this issue Oct 13, 2023 · 10 comments
Open
Labels
follow-up: chrome Needs a response from a Chrome representative proposal Proposal for a change or new feature supportive: firefox Supportive from Firefox supportive: safari Supportive from Safari

Comments

@fregante
Copy link

This was already requested in the previous thread, but it was probably too late by then, so I'll extract it into its own request


Could this be expanded to include the tab ID as well?

browser.runtime.getTarget(window) // {tabId: 1, frameId: 0}
browser.runtime.getTarget(iframe) // {tabId: 1, frameId: 63748}

It's a pretty common request to know "this" tab ID: https://stackoverflow.com/q/6202953/288906 (123 upvotes)

Currently this requires a ping to the runtime, which may or may not be "quick".

Including the recently-added documentId would be great. There's a lot of potential here so limiting it to just a frameId seems overly specific; returning an object makes it more flexible for future usage without having to create specific APIs.

@bershanskiy
Copy link
Member

Once browsers support both browser.runtime.getTarget() and chrome.runtime.getContexts(), one could trivially retrieve both tabId and documentId by combining them together. Of course, there is some inefficiency in two consecutive async calls and some potential data race in frames being navigated, loaded, etc.

@fregante
Copy link
Author

runtime.getContexts like extension.getViews is not available in content scripts, while runtime.getFrameId is only available in content scripts, so you can't combine the two.

@xeenon xeenon added supportive: safari Supportive from Safari proposal Proposal for a change or new feature and removed needs-triage labels Oct 18, 2023
@tophf
Copy link

tophf commented Oct 19, 2023

Ideally this info must be available synchronously because async call may take several seconds to complete on a slower device if the site is busy (e.g. compiling/running a big js or building its virtual DOM or whatever else). AFAIK documentId in Chrome is stored in the document's renderer, so it can be exposed as a field in chrome.runtime.

@Rob--W Rob--W added follow-up: chrome Needs a response from a Chrome representative supportive: firefox Supportive from Firefox labels Oct 26, 2023
@Rob--W
Copy link
Member

Rob--W commented Oct 26, 2023

I'm supportive of the capability requests, i.e. the ability to retrieve the current tabId/documentId, asynchronously.

I'd like this to be part of the "Contexts" feature (getContexts) rather than separate synchronous methods.
The runtime.getContexts() proposal at https://github.com/w3c/webextensions/blob/main/proposals/runtime_get_contexts.md includes the relevant part already:

### runtime.getCurrentContext()
We would like to provide an additional API, `runtime.getCurrentContext()`, to
return the calling context.
### Content Script Contexts
[Content scripts](https://developer.chrome.com/docs/extensions/mv3/content_scripts/)
run in a separate
[Renderer](https://developer.chrome.com/blog/inside-browser-part3/) (and
process) from the extension process. In this first version of the API, we will
not include these contexts due to the complexity it entails. However, we would
like to add these contexts in the future.
With the content script additions, we may add new fields to `ExtensionContext`,
such as `scriptUrl` (to indicate the content script's source).

@fregante
Copy link
Author

fregante commented Oct 27, 2023

That makes sense but then one has to match the objects returned with each <iframe> element manually. Also I'd need this API in the content script, not just on extension pages (unlike the previous getViews)

@Rob--W
Copy link
Member

Rob--W commented Oct 27, 2023

That makes sense but then one has to match the objects returned with each <iframe> element manually.

What is the use case for this?

Also I'd need this API in the content script, not just on extension pages (unlike the previous getViews)

In my comment I referenced the part of the proposal that calls out the potential to introduce getCurrentContext, AND making the concept available to content scripts.

@fregante
Copy link
Author

fregante commented Oct 27, 2023

In my comment

Sorry, on mobile the link opened the page without deep-linking, I didn't see the specific section.

That makes sense but then one has to match the objects returned with each <iframe> element manually.

What is the use case for this?

One of the usages was to enable communication between frames, e.g.:

  • the content script on the top frame
  • a chrome-extension:// document served in an iframe.

Other than postMessage, which isn't particularly convenient nor safe (#77), this can only be done:

  • from the content script:
    • with runtime.sendMessage(), which broadcasts to all contexts, so it needs a way to match sender.tabId === thisIframedDocument.tabId in the onMessage handler
  • from the frame:
    • with tabs.sendMessage(), which requires knowing which tab the current iframe is in

This new API would allow:

// From a `chrome-extension://` iframe to a `http://` top frame
const {tabId, iframeId} = await browser.runtime.getTarget(window.top)
chrome.tabs.sendMessage(tabId, message, {frameId})

and:

// From a `chrome-extension://` top frame to a `http://` iframe
const {tabId, iframeId} = await browser.runtime.getTarget($('iframe'))
chrome.tabs.sendMessage(tabId, message, {frameId})

or via runtime message routing in any direction


I suppose #77 would be a more direct solution to this, but it would not be enough "iframe to iframe" communication, because they don't have access to each other's iframe element.

@tophf
Copy link

tophf commented Oct 27, 2023

browser.runtime.getTarget($('iframe'))
browser.runtime.getTarget(window.top)

Since window.top is a Window, it would be more consistent to use frameElem.contentWindow here. It would also allow using a Window-typed event.source in a message.

@wfjsw
Copy link

wfjsw commented May 11, 2024

This is also important that this is synchronous as I can use this ID to do browser.scripting.executeScript on the page that the content script runs since the injection.target is mandatory and acquiring this asynchronously would miss the document-start timepoint.


I'm looking for a way to securely do sendMessage from MAIN world script to background service worker. Currently it would be impossible to do this without involving postMessage.

@tophf
Copy link

tophf commented May 11, 2024

@wfjsw, it's not possible to achieve a real document_start with executeScript because it injects asynchronously, messaging is asynchronous as well. A real document_start can be achieved by using a declared or registered content script (chrome.scripting.registerContentScripts).

I'm looking for a way to securely do sendMessage from MAIN world script to background service worker. Currently it would be impossible to do this without involving postMessage.

It will be implemented as a separate API to communicate between the worlds securely. Note that your code in the MAIN world may run in an already poisoned JS environment (https://crbug.com/40202434 applies to all browsers). Currently the only secure way is to create a temporary iframe to extract dispatchEvent/addEventListener/etc. to establish a secure channel, it's very complicated and you can see how it's done in Violentmonkey. In ManifestV3 it requires using the userScripts API permission, which is problematic because it misrepresents the function of the extensions, also users in Chrome must enable "developer mode" in chrome://extensions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
follow-up: chrome Needs a response from a Chrome representative proposal Proposal for a change or new feature supportive: firefox Supportive from Firefox supportive: safari Supportive from Safari
Projects
None yet
Development

No branches or pull requests

6 participants