cookieContextId -> userContextId

This commit is contained in:
Abe Jellinek 2026-04-22 10:33:45 -04:00
parent 5ebe8ea15f
commit de5bc7c5c5
8 changed files with 45 additions and 47 deletions

View file

@ -11,7 +11,7 @@ export class ZoteroWebTranslationEnvironment extends AbstractWebTranslationEnvir
const { HiddenBrowser } = ChromeUtils.importESModule('chrome://zotero/content/HiddenBrowser.mjs');
let browser = new HiddenBrowser({
docShell: { allowMetaRedirects: true },
cookieContextId: tester.cookieSandbox,
userContextId: tester.cookieSandbox,
});
await browser.load(url, { requireSuccessfulStatus: true });

View file

@ -48,8 +48,7 @@ export class HiddenBrowser {
* @param {Boolean} [options.blockRemoteResources] Block all remote (non-file:) resources
* @param {Boolean} [options.useHiddenFrame=true] Use a hidden frame to create the browser.
* Must be set to false if intending to call print().
* @param {Number} [options.cookieContextId] - userContextId from Zotero.HTTP.newCookieContext()
* for cookie isolation
* @param {Number} [options.userContextId] - From Zotero.HTTP.newCookieContext() for cookie isolation
* @param {String} [options.customUserAgent] - Override User-Agent for all requests
* from this browser's browsing context
*/
@ -83,8 +82,8 @@ export class HiddenBrowser {
browser.setAttribute("remote", "true");
browser.setAttribute('maychangeremoteness', 'true');
browser.setAttribute("disableglobalhistory", "true");
if (options.cookieContextId) {
browser.setAttribute("usercontextid", String(options.cookieContextId));
if (options.userContextId) {
browser.setAttribute("usercontextid", String(options.userContextId));
}
browser.style.display = "none";
doc.documentElement.appendChild(browser);

View file

@ -160,7 +160,7 @@ const obtainReferenceManagerToken = async (login, password) => {
let { HiddenBrowser } = ChromeUtils.importESModule("chrome://zotero/content/HiddenBrowser.mjs");
let cookieContext = Zotero.HTTP.newCookieContext();
let browser = new HiddenBrowser({
cookieContextId: cookieContext.id,
userContextId: cookieContext.id,
docShell: {
allowMetaRedirects: true,
allowAuth: true,

View file

@ -35,13 +35,13 @@ window.addEventListener("load", /*async */function () {
let { uri, options } = window.arguments[0].wrappedJSObject;
browser = document.querySelector('browser');
if (options?.cookieContextId) {
if (options?.userContextId) {
// Set usercontextid on new <browser> so it takes effect
let newBrowser = document.createXULElement('browser');
for (let { name, value } of browser.attributes) {
newBrowser.setAttribute(name, value);
}
newBrowser.setAttribute('usercontextid', String(options.cookieContextId));
newBrowser.setAttribute('usercontextid', String(options.userContextId));
browser.replaceWith(newBrowser);
browser = newBrowser;
}
@ -56,7 +56,7 @@ window.addEventListener("load", /*async */function () {
}
window.viewerOriginalURI = uri;
window.viewerCookieContextId = options?.cookieContextId;
window.viewerUserContextId = options?.userContextId;
loadURI(Services.io.newURI(uri), options);
}, false);

View file

@ -78,7 +78,7 @@ Zotero.BrowserRequest = {
* client-side redirects or cookie-setting challenges to settle.
*
* Cookies acquired by the browser remain in the shared jar keyed on
* cookieContextId; a subsequent Zotero.HTTP.request using the same ID will
* userContextId; a subsequent Zotero.HTTP.request using the same ID will
* see them.
*
* On timeout, if the page contains the entry's captchaLocator and
@ -86,7 +86,7 @@ Zotero.BrowserRequest = {
*
* @param {string} url
* @param {object} [options]
* @param {number} [options.cookieContextId]
* @param {number} [options.userContextId]
* @param {object} [options.entry] - registry entry controlling escalation
* @param {boolean} [options.allowViewer=false]
* @returns {Promise<void>}
@ -94,13 +94,13 @@ Zotero.BrowserRequest = {
async clearChallenge(url, options = {}) {
Zotero.debug(`BrowserRequest: Clearing challenge at ${url}`);
let { cookieContextId, entry, allowViewer = false } = options;
let { userContextId, entry, allowViewer = false } = options;
let successCookie = entry?.successCookie;
// Capture the cookie's current value (if any) before the attempt so
// we can tell a freshly-issued cookie from a stale one left over from
// a previous session.
let initialCookieValue = successCookie
? this._readCookieValue({ ...successCookie, cookieContextId })
? this._readCookieValue({ ...successCookie, userContextId })
: null;
// Cloudflare Turnstile rejects the "Zotero/[version]" suffix.
// A plain Firefox UA on just this browsing context lets the widget run.
@ -111,11 +111,11 @@ Zotero.BrowserRequest = {
// before the page fully settles (or redirects somewhere else).
let hiddenBrowser;
try {
hiddenBrowser = new HiddenBrowser({ cookieContextId, customUserAgent });
hiddenBrowser = new HiddenBrowser({ userContextId, customUserAgent });
await hiddenBrowser._createdPromise;
await this._loadAndSettle(hiddenBrowser, url, {
successCookie,
cookieContextId
userContextId
});
}
catch (e) {
@ -129,7 +129,7 @@ Zotero.BrowserRequest = {
}
if (successCookie) {
let currentValue = this._readCookieValue({ ...successCookie, cookieContextId });
let currentValue = this._readCookieValue({ ...successCookie, userContextId });
if (currentValue && currentValue !== initialCookieValue) {
return;
}
@ -144,14 +144,14 @@ Zotero.BrowserRequest = {
Zotero.debug(`BrowserRequest: Escalating to viewer for ${url}`);
if (successCookie) {
await this._loadAndWaitForCookieInViewer(url, {
cookieContextId,
userContextId,
customUserAgent,
successCookie
});
return;
}
await this.clearChallengeInViewer(url, {
cookieContextId,
userContextId,
captchaLocator: entry.captchaLocator
});
},
@ -165,7 +165,7 @@ Zotero.BrowserRequest = {
async _loadAndWaitForCookieInViewer(url, options) {
Zotero.debug(`BrowserRequest: Awaiting user challenge clearance (cookie ${options.successCookie.name}) at ${url}`);
const timeout = Zotero.Prefs.get('browserRequest.timeout');
const { successCookie, cookieContextId, customUserAgent } = options;
const { successCookie, userContextId, customUserAgent } = options;
let win, wmListener, pollInterval;
let done = false;
@ -178,14 +178,14 @@ Zotero.BrowserRequest = {
});
Services.wm.addListener(wmListener);
await new Promise((resolve) => {
win = Zotero.openInViewer(url, { cookieContextId, customUserAgent });
win = Zotero.openInViewer(url, { userContextId, customUserAgent });
win.addEventListener('load', resolve);
});
Zotero.Utilities.Internal.activate(win);
pollInterval = this._pollForCookie({
successCookie,
cookieContextId,
userContextId,
onFound: () => {
done = true;
cookieDeferred.resolve();
@ -213,11 +213,11 @@ Zotero.BrowserRequest = {
* Read the value of a named cookie on a given host under an optional
* userContextId. Returns null if the cookie is absent.
*/
_readCookieValue({ host, name, cookieContextId }) {
_readCookieValue({ host, name, userContextId }) {
try {
let cookies = Services.cookies.getCookiesFromHost(
host,
cookieContextId ? { userContextId: cookieContextId } : {}
userContextId ? { userContextId } : {}
);
for (let cookie of cookies) {
if (cookie.name === name) {
@ -262,16 +262,16 @@ Zotero.BrowserRequest = {
*
* @param {object} opts
* @param {{host: string, name: string}} opts.successCookie
* @param {number} [opts.cookieContextId]
* @param {number} [opts.userContextId]
* @param {Function} opts.onFound
* @param {number} [opts.intervalMs=250]
* @returns {number} interval handle
*/
_pollForCookie({ successCookie, cookieContextId, onFound, intervalMs = 250 }) {
_pollForCookie({ successCookie, userContextId, onFound, intervalMs = 250 }) {
let { host, name } = successCookie;
let initialValue = this._readCookieValue({ host, name, cookieContextId });
let initialValue = this._readCookieValue({ host, name, userContextId });
return setInterval(() => {
let currentValue = this._readCookieValue({ host, name, cookieContextId });
let currentValue = this._readCookieValue({ host, name, userContextId });
if (currentValue && currentValue !== initialValue) {
onFound();
}
@ -285,7 +285,7 @@ Zotero.BrowserRequest = {
*
* @param {string} url
* @param {object} options
* @param {number} [options.cookieContextId]
* @param {number} [options.userContextId]
* @param {string} options.captchaLocator
* @returns {Promise<void>}
*/
@ -306,7 +306,7 @@ Zotero.BrowserRequest = {
Services.wm.addListener(wmListener);
await new Promise((resolve) => {
win = Zotero.openInViewer(url, {
cookieContextId: options.cookieContextId
userContextId: options.userContextId
});
win.addEventListener('load', resolve);
});
@ -407,7 +407,7 @@ Zotero.BrowserRequest = {
* @param {object} [opts]
* @param {(blob: Blob) => void} [opts.onPDF]
* @param {{ host: string, name: string }} [opts.successCookie]
* @param {number} [opts.cookieContextId]
* @param {number} [opts.userContextId]
* @returns {Promise<void>}
*/
async _loadAndSettle(hiddenBrowser, url, opts = {}) {
@ -455,7 +455,7 @@ Zotero.BrowserRequest = {
if (opts.successCookie) {
cookiePollInterval = this._pollForCookie({
successCookie: opts.successCookie,
cookieContextId: opts.cookieContextId,
userContextId: opts.userContextId,
onFound: () => {
Zotero.debug(`BrowserRequest: successCookie ${opts.successCookie.name} appeared`);
cookieDeferred.resolve();

View file

@ -116,7 +116,7 @@ Zotero.HTTP = new function () {
// Base for generated userContextIds -- high to avoid collision with Firefox containers
var _nextCookieContextId = 100000 + Math.floor(Math.random() * 100000);
var _nextUserContextId = 100000 + Math.floor(Math.random() * 100000);
/**
* Create an isolated cookie context backed by a unique Mozilla userContextId.
@ -128,7 +128,7 @@ Zotero.HTTP = new function () {
* @return {{ id: number, getCookies: (host: string) => nsICookie[], dispose: () => void }}
*/
this.newCookieContext = function () {
let id = _nextCookieContextId++;
let id = _nextUserContextId++;
return {
id,
/**
@ -174,8 +174,7 @@ Zotero.HTTP = new function () {
* @param {Number[]|false} [options.successCodes] - HTTP status codes that are considered
* successful, or FALSE to allow all
* @param {Boolean} [options.anon] - Make the request anonymously, without global cookies
* @param {Number} [options.cookieContextId] - userContextId from newCookieContext() for
* cookie isolation
* @param {Number} [options.userContextId] - From newCookieContext() for cookie isolation
* @param {Number} [options.timeout = 30000] - Request timeout specified in milliseconds, or 0
* for no timeout
* @param {Number[]} [options.errorDelayIntervals] - Array of milliseconds to wait before
@ -300,7 +299,7 @@ Zotero.HTTP = new function () {
// Translation framework uses cookieSandbox to hold userContextId number
if (typeof options.cookieSandbox === 'number') {
options.cookieContextId = options.cookieSandbox;
options.userContextId = options.cookieSandbox;
delete options.cookieSandbox;
}
@ -335,8 +334,8 @@ Zotero.HTTP = new function () {
xmlhttp.open(method, url, true, options.username, options.password);
// Isolate cookies into a separate jar via userContextId
if (options.cookieContextId && xmlhttp.setOriginAttributes) {
xmlhttp.setOriginAttributes({ userContextId: options.cookieContextId });
if (options.userContextId && xmlhttp.setOriginAttributes) {
xmlhttp.setOriginAttributes({ userContextId: options.userContextId });
}
// Pass the request to a callback

View file

@ -1238,7 +1238,7 @@ const { CommandLineOptions } = ChromeUtils.importESModule("chrome://zotero/conte
* @param {Object} [options]
* @param {Function} [options.onLoad] - Function to run once URI is loaded; passed the loaded document
* @param {Boolean} [options.allowJavaScript] - Set to false to disable JavaScript
* @param {Number} [options.cookieContextId] - userContextId to isolate the viewer's cookies
* @param {Number} [options.userContextId] - To isolate the viewer's cookies
* into the same jar as a Zotero.HTTP.request or HiddenBrowser using the same ID
* @param {String} [options.customUserAgent] - Override the User-Agent for all requests
* from this viewer's browsing context
@ -1251,7 +1251,7 @@ const { CommandLineOptions } = ChromeUtils.importESModule("chrome://zotero/conte
var viewerWins = Services.wm.getEnumerator("zotero:basicViewer");
for (let existingWin of viewerWins) {
if (existingWin.viewerOriginalURI === uri && existingWin.viewerCookieContextId === options?.cookieContextId) {
if (existingWin.viewerOriginalURI === uri && existingWin.viewerUserContextId === options?.userContextId) {
existingWin.focus();
return existingWin;
}

View file

@ -426,7 +426,7 @@ describe("Zotero.HTTP", function () {
// Request in the isolated context should not see the default cookie
let req = await Zotero.HTTP.request('GET', cookieURL, {
cookieContextId: ctx.id,
userContextId: ctx.id,
successCodes: false
});
assert.equal(req.status, 403);
@ -441,14 +441,14 @@ describe("Zotero.HTTP", function () {
try {
// First request in context -- gets 403, sets cookie
let req = await Zotero.HTTP.request('GET', cookieURL, {
cookieContextId: ctx.id,
userContextId: ctx.id,
successCodes: false
});
assert.equal(req.status, 403);
// Second request in same context -- should have the cookie
req = await Zotero.HTTP.request('GET', cookieURL, {
cookieContextId: ctx.id,
userContextId: ctx.id,
successCodes: false
});
assert.equal(req.status, 200);
@ -464,13 +464,13 @@ describe("Zotero.HTTP", function () {
try {
// Set cookie in ctx1
await Zotero.HTTP.request('GET', cookieURL, {
cookieContextId: ctx1.id,
userContextId: ctx1.id,
successCodes: false
});
// ctx2 should not see ctx1's cookie
let req = await Zotero.HTTP.request('GET', cookieURL, {
cookieContextId: ctx2.id,
userContextId: ctx2.id,
successCodes: false
});
assert.equal(req.status, 403);
@ -486,7 +486,7 @@ describe("Zotero.HTTP", function () {
// Set cookie in context
await Zotero.HTTP.request('GET', cookieURL, {
cookieContextId: ctx.id,
userContextId: ctx.id,
successCodes: false
});
@ -499,7 +499,7 @@ describe("Zotero.HTTP", function () {
let ctx2 = Zotero.HTTP.newCookieContext();
try {
let req = await Zotero.HTTP.request('GET', cookieURL, {
cookieContextId: ctx.id,
userContextId: ctx.id,
successCodes: false
});
assert.equal(req.status, 403);