Block remote content when indexing HTML file (#3157)

This commit is contained in:
Abe Jellinek 2023-06-12 23:43:18 -04:00 committed by GitHub
parent 30624c6aba
commit 2639981dda
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 1 deletions

View file

@ -62,6 +62,7 @@ const HiddenBrowser = {
* @param {Boolean} [options.allowJavaScript] * @param {Boolean} [options.allowJavaScript]
* @param {Object} [options.docShell] Fields to set on Browser.docShell * @param {Object} [options.docShell] Fields to set on Browser.docShell
* @param {Boolean} [options.requireSuccessfulStatus] * @param {Boolean} [options.requireSuccessfulStatus]
* @param {Boolean} [options.blockRemoteResources] Block all remote (non-file:) resources
* @param {Zotero.CookieSandbox} [options.cookieSandbox] * @param {Zotero.CookieSandbox} [options.cookieSandbox]
*/ */
async create(source, options = {}) { async create(source, options = {}) {
@ -108,6 +109,10 @@ const HiddenBrowser = {
}, 1000 * 60); }, 1000 * 60);
} }
if (options.blockRemoteResources) {
RemoteResourceBlockingObserver.watch(browser);
}
// Next bit adapted from Mozilla's HeadlessShell.jsm // Next bit adapted from Mozilla's HeadlessShell.jsm
const principal = Services.scriptSecurityManager.getSystemPrincipal(); const principal = Services.scriptSecurityManager.getSystemPrincipal();
try { try {
@ -229,9 +234,43 @@ const HiddenBrowser = {
destroy(browser) { destroy(browser) {
var frame = browserFrameMap.get(browser); var frame = browserFrameMap.get(browser);
if (frame) { if (frame) {
RemoteResourceBlockingObserver.unwatch(browser);
frame.destroy(); frame.destroy();
Zotero.debug("Deleted hidden browser"); Zotero.debug("Deleted hidden browser");
browserFrameMap.delete(browser); browserFrameMap.delete(browser);
} }
} }
}; };
const RemoteResourceBlockingObserver = {
_observerAdded: false,
_ids: new Set(),
observe(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
let id = Zotero.platformMajorVersion > 102 ? channel.browserId : channel.topBrowsingContextId;
if (this._ids.has(id) && channel.URI.scheme !== 'file') {
channel.cancel(Cr.NS_BINDING_ABORTED);
}
},
watch(browser) {
let id = Zotero.platformMajorVersion > 102 ? browser.browserId : browser.browsingContext.id;
this._ids.add(id);
if (!this._observerAdded) {
Services.obs.addObserver(this, 'http-on-modify-request');
Zotero.debug('RemoteResourceBlockingObserver: Added observer');
this._observerAdded = true;
}
},
unwatch(browser) {
let id = Zotero.platformMajorVersion > 102 ? browser.browserId : browser.browsingContext.id;
this._ids.delete(id);
if (this._observerAdded && !this._ids.size) {
Services.obs.removeObserver(this, 'http-on-modify-request');
Zotero.debug('RemoteResourceBlockingObserver: Removed observer');
this._observerAdded = false;
}
}
};

View file

@ -1541,7 +1541,7 @@ Zotero.Fulltext = Zotero.FullText = new function(){
var pageData; var pageData;
try { try {
let url = Zotero.File.pathToFileURI(path); let url = Zotero.File.pathToFileURI(path);
browser = await HiddenBrowser.create(url); browser = await HiddenBrowser.create(url, { blockRemoteResources: true });
pageData = await HiddenBrowser.getPageData(browser, ['characterSet', 'bodyText']); pageData = await HiddenBrowser.getPageData(browser, ['characterSet', 'bodyText']);
} }
finally { finally {

View file

@ -8,12 +8,30 @@ describe("HiddenBrowser", function() {
var port = 16213; var port = 16213;
var baseURL = `http://127.0.0.1:${port}/`; var baseURL = `http://127.0.0.1:${port}/`;
var pngRequested = false;
before(function () { before(function () {
Cu.import("resource://zotero-unit/httpd.js"); Cu.import("resource://zotero-unit/httpd.js");
httpd = new HttpServer(); httpd = new HttpServer();
httpd.start(port); httpd.start(port);
}); });
beforeEach(async function () {
pngRequested = false;
httpd.registerPathHandler(
'/remote.png',
{
handle: function (request, response) {
Zotero.debug('Something loaded the image')
response.setHeader('Content-Type', 'image/png', false);
response.setStatusLine(null, 200, 'OK');
response.write('');
pngRequested = true;
}
}
);
});
after(async function () { after(async function () {
await new Promise(resolve => httpd.stop(resolve)); await new Promise(resolve => httpd.stop(resolve));
}); });
@ -22,6 +40,22 @@ describe("HiddenBrowser", function() {
let e = await getPromiseError(HiddenBrowser.create(baseURL + 'nonexistent', { requireSuccessfulStatus: true })); let e = await getPromiseError(HiddenBrowser.create(baseURL + 'nonexistent', { requireSuccessfulStatus: true }));
assert.instanceOf(e, Zotero.HTTP.UnexpectedStatusException); assert.instanceOf(e, Zotero.HTTP.UnexpectedStatusException);
}); });
it("should prevent a remote request with blockRemoteResources", async function () {
let path = OS.Path.join(getTestDataDirectory().path, 'test-hidden.html');
let browser = await HiddenBrowser.create(path, { blockRemoteResources: true });
await HiddenBrowser.getPageData(browser, ['characterSet', 'bodyText']);
HiddenBrowser.destroy(browser);
assert.isFalse(pngRequested);
});
it("should allow a remote request without blockRemoteResources", async function () {
let path = OS.Path.join(getTestDataDirectory().path, 'test-hidden.html');
let browser = await HiddenBrowser.create(path, { blockRemoteResources: false });
await HiddenBrowser.getPageData(browser, ['characterSet', 'bodyText']);
HiddenBrowser.destroy(browser);
assert.isTrue(pngRequested);
});
}); });
describe("#getPageData()", function () { describe("#getPageData()", function () {

View file

@ -3,6 +3,7 @@
<meta charset="utf-8"/> <meta charset="utf-8"/>
</head> </head>
<body> <body>
<img src="http://127.0.0.1:16213/remote.png">
<p>This is a test.</p> <p>This is a test.</p>
<p style="display: none">This is hidden text.</p> <p style="display: none">This is hidden text.</p>
</body> </body>