w3c / webextensions

Charter and administrivia for the WebExtensions Community Group (WECG)
Other
591 stars 54 forks source link

Blocking webRequest usecase - GM_xmlhttpRequest for Tampermonkey/Violentmonkey userscripts #176

Open tophf opened 2 years ago

tophf commented 2 years ago

GM_xmlhttpRequest/GM.xmlHttpRequest is a foundational feature for userscripts.

It needs the ability to set custom HTTP headers from the "forbidden" list e.g. cookie-related headers to implement proper isolation of cookies in incognito mode, otherwise userscripts running there would enable passive tracking of the main profile.

The declarativeNetRequest API cannot be used because its rules cannot be scoped to an individual request, only to the entire tab, which may have a lot of frames and a lot of different userscripts making overlapped requests. Currently, a blocking webRequest is used by Tampermonkey/Violentmonkey to set a dummy temporary header (removed in onBeforeSendHeaders) with a random id that's used to map the request's id in further events.

dotproto commented 2 years ago

@tophf, I don't understand the association between request cookies and the user's main profile. To my knowledge Chrome's incognito implementation creates a temporary profile that's discarded when the incognito session ends. As such, there shouldn't be a need for user scripts to remove cookies from requests modification to remove main profile cookies from incognito requests. Am I missing something?

tophf commented 2 years ago

Extensions in the default spanning mode for incognito use the same background script and the same cookie store as the main profile.

Either way, the tracking problem is just one example. Userscripts also need to set/get a cookie explicitly just for a request, without affecting the main profile. Userscripts also often need to set Referer, for which there's no other way than to use a blocking webRequest. Maybe other headers from that list too.

Without a blocking webRequest we need another way to track the lifecycle of the request made via fetch in the background script or XMLHttpRequest in a tab via observational webRequest.

As I explained declarativeNetRequest can't be used now because we would have to allow just one request at a time in the entire browser to be able to track it reliably via the observational webRequest. Maybe it can be extended in the future e.g. by adding a condition for the request like headerFilter so we set a dummy value there in fetch, add a dynamic rule in DNR to set the necessary headers for just this one request. Still, it won't help with receiving the set-cookie header, reading it, and stripping it to prevent it affecting the main profile.

Anyway, currently this is purely academic because ManifestV3 still doesn't have a solution for userscript extensions.

dotproto commented 2 years ago

Thanks for calling out spanning mode; that slipped my mind.

My first impression is that it may be best for browsers to consider directly supporting more of GM.xmlHttpRequest's capabilities rather than requiring extension authors to. Perhaps when we add user script support to the scripting API we could/should also support GM APIs. Maybe even without that prefix or with different one?

tophf commented 2 years ago

Native support would be a nice feature, especially if the browser can show a native confirmation dialog for the URL per the satellite @connect declaration in the userscript's header, which currently is only implemented in Tampermonkey. These keys list the sites that the userscript can connect to: the explicitly listed sites will be silently allowed because they're granted at the install time, whereas * will display a dialog whenever an unknown site is accessed with a few buttons: allow, deny, [x] remember.

derjanb commented 2 years ago

My first impression is that it may be best for browsers to consider directly supporting more of GM.xmlHttpRequest's capabilities rather than requiring extension authors to.

As a starting point allowing fetch to set all headers even the "forbidden" ones would be great.

Another thing would be raw access to the received headers or even better a way to modify them before they are processed by the browser. So basically blocking webRequest functionality but only for this request. Maybe this can be implemented with a RequestController similar to the AbortController [edit] or by enabling FetchEvent for the extension's own requests?[/edit]

we could/should also support GM APIs.

I think there a lot more extensions that modify their own request via webRequest to fit their needs. So I'd favor a more general solution, except this is what you mean with "support GM APIs".

CodFrm commented 9 months ago

The deadline for manifest v3 has been determined. Is there still no solution to this problem?