Tampermonkey / tampermonkey

Tampermonkey is the most popular userscript manager, with over 10 million users. It's available for Chrome, Microsoft Edge, Safari, Opera Next, and Firefox.
GNU General Public License v3.0
4.04k stars 414 forks source link

GM.xmlHttpRequest not sending 3rd-party cookies that have "partitioned" attribute #2057

Closed anonghuser closed 1 week ago

anonghuser commented 2 months ago

Since around the middle of 2023, chrome supports a new experimental attribute on cookies: see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#partitioned and https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies

It might be good for assuring users the cookie can not be used to track them across different sites, but It's breaking some use cases of GM.xhr For example, cloudflare adds this attribute to its anti-bot protection cookies and so GM.xhr returns HTTP 403 even for sites that the user has visited and already manually passed the anti-bot captcha.

It would be nice if GM.xhr can get an additional flag about whether to use the current tab's partition, or the partition of the site specified in its url argument.

anonghuser commented 2 months ago

To test, you can set a partitioned cookie on httpbin.org by visiting this url: https://httpbin.org/response-headers?set-cookie=partitioned=works;path=/;expires=Wed,%2021%20Sep%202033%2015:59:37%20GMT;httponly;secure;samesite=none;partitioned as well as a non-partitioned one: https://httpbin.org/response-headers?set-cookie=nonpartitioned=works;path=/;expires=Wed,%2021%20Sep%202033%2015:59:37%20GMT;httponly;secure;samesite=none and then try to fetch https://httpbin.org/cookies via GM.xhr in a userscript running on any other site.

// ==UserScript==
// @name         xxx
// @namespace    xxx
// @version      xxx
// @description  xxx
// @author       xxx
// @match        https://*/*
// @grant        GM.xmlHttpRequest
// @connect      httpbin.org
// ==/UserScript==
GM.xmlHttpRequest({
  url: 'https://httpbin.org/cookies',
  onload: r=>console.log(r.responseText),
  onerror: console.error,
})
derjanb commented 2 months ago

You can play with GM_cookie and GM_xmlhttpRequest.cookiePartition at 5.2.6196 (crx|xpi in review)

Chrome/Edge users, please download the crx file linked above and drag and drop it to the extensions page chrome://extensions (after you've enabled 'Developer Mode'). Firefox users please install the BETA version or check for BETA version updates at about:addons

For a quick fix please export your settings and scripts as zip or (JSON) file at the "Utilities" tab and import it back at the fixed BETA version.

// ==UserScript==
// @name         xxx
// @namespace    xxx
// @version      xxx
// @description  xxx
// @author       xxx
// @match        https://*/*
// @grant        GM.xmlHttpRequest
// @connect      httpbin.org
// ==/UserScript==
GM.xmlHttpRequest({
  url: 'https://httpbin.org/cookies',
  onload: r=>console.log(r.responseText),
  onerror: console.error,
  cookiePartition: {
      topLevelSite: 'https://httpbin.org'
  }
})
anonghuser commented 1 month ago

Thank you for the response and the quick implementation. It works as advertised :) While I was testing it I passed a topLevelSite value with an ending slash (I used new URL('/', url) since I didn't think of new URL(url).origin) and the call hanged for a long time, or called the onerror handler with a background shutdown error inconsistently, i.e. sometimes after just 1-3 seconds, sometimes much longer, sometimes it didn't seem like it'd ever finish even after several minutes of waiting. Please consider using just the origin of the passed value if that's what is required by the internal apis, or at least showing a clearer error message when an invalid value is passed since I expect other people might make the same mistake as me.