ma1 pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser
Commits:
-
b45800e4
by Tom Schuster at 2025-08-18T13:29:21+02:00
-
983d70a3
by Tom Schuster at 2025-08-18T13:29:22+02:00
-
49e5d8b9
by Tom Schuster at 2025-08-18T13:29:24+02:00
11 changed files:
- browser/actors/ClickHandlerChild.sys.mjs
- browser/app/profile/firefox.js
- browser/base/content/test/general/browser_modifiedclick_inherit_principal.js
- browser/base/content/test/linkHandling/browser.toml
- browser/base/content/test/linkHandling/browser_contentAreaClick_subframe_javascript.js
- + browser/base/content/test/linkHandling/browser_javascript_links.js
- + browser/base/content/test/linkHandling/file_javascript_links_subframe.html
- dom/base/nsObjectLoadingContent.cpp
- modules/libpref/init/StaticPrefList.yaml
- testing/web-platform/tests/html/semantics/embedded-content/the-object-element/historical.html
- widget/gtk/nsClipboard.cpp
Changes:
| ... | ... | @@ -12,12 +12,26 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 12 | 12 | E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
|
| 13 | 13 | });
|
| 14 | 14 | |
| 15 | +XPCOMUtils.defineLazyPreferenceGetter(
|
|
| 16 | + lazy,
|
|
| 17 | + "autoscrollEnabled",
|
|
| 18 | + "general.autoScroll",
|
|
| 19 | + true
|
|
| 20 | +);
|
|
| 21 | + |
|
| 22 | +XPCOMUtils.defineLazyPreferenceGetter(
|
|
| 23 | + lazy,
|
|
| 24 | + "blockJavascript",
|
|
| 25 | + "browser.link.alternative_click.block_javascript",
|
|
| 26 | + true
|
|
| 27 | +);
|
|
| 28 | + |
|
| 15 | 29 | export class MiddleMousePasteHandlerChild extends JSWindowActorChild {
|
| 16 | 30 | handleEvent(clickEvent) {
|
| 17 | 31 | if (
|
| 18 | 32 | clickEvent.defaultPrevented ||
|
| 19 | 33 | clickEvent.button != 1 ||
|
| 20 | - MiddleMousePasteHandlerChild.autoscrollEnabled
|
|
| 34 | + lazy.autoscrollEnabled
|
|
| 21 | 35 | ) {
|
| 22 | 36 | return;
|
| 23 | 37 | }
|
| ... | ... | @@ -34,13 +48,6 @@ export class MiddleMousePasteHandlerChild extends JSWindowActorChild { |
| 34 | 48 | }
|
| 35 | 49 | }
|
| 36 | 50 | |
| 37 | -XPCOMUtils.defineLazyPreferenceGetter(
|
|
| 38 | - MiddleMousePasteHandlerChild,
|
|
| 39 | - "autoscrollEnabled",
|
|
| 40 | - "general.autoScroll",
|
|
| 41 | - true
|
|
| 42 | -);
|
|
| 43 | - |
|
| 44 | 51 | export class ClickHandlerChild extends JSWindowActorChild {
|
| 45 | 52 | handleEvent(wrapperEvent) {
|
| 46 | 53 | this.handleClickEvent(wrapperEvent.sourceEvent);
|
| ... | ... | @@ -112,6 +119,14 @@ export class ClickHandlerChild extends JSWindowActorChild { |
| 112 | 119 | };
|
| 113 | 120 | |
| 114 | 121 | if (href && !isFromMiddleMousePasteHandler) {
|
| 122 | + if (
|
|
| 123 | + lazy.blockJavascript &&
|
|
| 124 | + Services.io.extractScheme(href) == "javascript"
|
|
| 125 | + ) {
|
|
| 126 | + // We don't want to open new tabs or windows for javascript: links.
|
|
| 127 | + return;
|
|
| 128 | + }
|
|
| 129 | + |
|
| 115 | 130 | try {
|
| 116 | 131 | Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
|
| 117 | 132 | principal,
|
| ... | ... | @@ -907,6 +907,9 @@ pref("browser.link.open_newwindow.restriction", 2); |
| 907 | 907 | pref("browser.link.open_newwindow.disabled_in_fullscreen", false);
|
| 908 | 908 | #endif
|
| 909 | 909 | |
| 910 | +// If true, opening javscript: URLs using middle-click, CTRL+click etc. are blocked.
|
|
| 911 | +pref("browser.link.alternative_click.block_javascript", true);
|
|
| 912 | + |
|
| 910 | 913 | // Tabbed browser
|
| 911 | 914 | pref("browser.tabs.closeTabByDblclick", false);
|
| 912 | 915 | pref("browser.tabs.closeWindowWithLastTab", true);
|
| ... | ... | @@ -10,6 +10,10 @@ const kURL = |
| 10 | 10 | * we use the correct principal, and we don't clear the URL bar.
|
| 11 | 11 | */
|
| 12 | 12 | add_task(async function () {
|
| 13 | + await SpecialPowers.pushPrefEnv({
|
|
| 14 | + set: [["browser.link.alternative_click.block_javascript", false]],
|
|
| 15 | + });
|
|
| 16 | + |
|
| 13 | 17 | await BrowserTestUtils.withNewTab(kURL, async function (browser) {
|
| 14 | 18 | let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
|
| 15 | 19 | await SpecialPowers.spawn(browser, [], async function () {
|
| ... | ... | @@ -2,3 +2,8 @@ |
| 2 | 2 | support-files = [
|
| 3 | 3 | "file_contentAreaClick_subframe_javascript.html"
|
| 4 | 4 | ]
|
| 5 | + |
|
| 6 | +["browser_javascript_links.js"]
|
|
| 7 | +support-files = [
|
|
| 8 | + "file_javascript_links_subframe.html"
|
|
| 9 | +] |
| ... | ... | @@ -5,6 +5,10 @@ const gExampleComRoot = getRootDirectory(gTestPath).replace( |
| 5 | 5 | const IFRAME_FILE = "file_contentAreaClick_subframe_javascript.html";
|
| 6 | 6 | |
| 7 | 7 | add_task(async function () {
|
| 8 | + await SpecialPowers.pushPrefEnv({
|
|
| 9 | + set: [["browser.link.alternative_click.block_javascript", false]],
|
|
| 10 | + });
|
|
| 11 | + |
|
| 8 | 12 | await BrowserTestUtils.withNewTab(
|
| 9 | 13 | `data:text/html,<iframe src="${gExampleComRoot + IFRAME_FILE}"></iframe>`,
|
| 10 | 14 | async browser => {
|
| 1 | +/* Any copyright is dedicated to the Public Domain.
|
|
| 2 | + * http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
| 3 | + |
|
| 4 | +"use strict";
|
|
| 5 | + |
|
| 6 | +const TEST_PATH = getRootDirectory(gTestPath).replace(
|
|
| 7 | + "chrome://mochitests/content/",
|
|
| 8 | + "https://example.com/"
|
|
| 9 | +);
|
|
| 10 | +const IFRAME_PATH = TEST_PATH + "file_javascript_links_subframe.html";
|
|
| 11 | + |
|
| 12 | +add_setup(async function () {
|
|
| 13 | + await SpecialPowers.pushPrefEnv({
|
|
| 14 | + set: [
|
|
| 15 | + ["browser.link.alternative_click.block_javascript", true],
|
|
| 16 | + ["browser.tabs.opentabfor.middleclick", true],
|
|
| 17 | + ["middlemouse.paste", false],
|
|
| 18 | + ["middlemouse.contentLoadURL", false],
|
|
| 19 | + ["general.autoScroll", false],
|
|
| 20 | + ],
|
|
| 21 | + });
|
|
| 22 | +});
|
|
| 23 | + |
|
| 24 | +add_task(async function () {
|
|
| 25 | + await BrowserTestUtils.withNewTab(
|
|
| 26 | + `data:text/html,<a href="javascript:alert(1);">click me`,
|
|
| 27 | + async browser => {
|
|
| 28 | + await BrowserTestUtils.synthesizeMouseAtCenter(
|
|
| 29 | + "a",
|
|
| 30 | + { button: 0, ctrlKey: true, metaKey: true },
|
|
| 31 | + browser
|
|
| 32 | + );
|
|
| 33 | + is(
|
|
| 34 | + gBrowser.tabs.length,
|
|
| 35 | + 2,
|
|
| 36 | + "Accel+click on javascript: link shouldn't open a new tab"
|
|
| 37 | + );
|
|
| 38 | + |
|
| 39 | + await BrowserTestUtils.synthesizeMouseAtCenter(
|
|
| 40 | + "a",
|
|
| 41 | + { button: 1 },
|
|
| 42 | + browser
|
|
| 43 | + );
|
|
| 44 | + is(
|
|
| 45 | + gBrowser.tabs.length,
|
|
| 46 | + 2,
|
|
| 47 | + "Middle click on javascript: link shouldn't open a new tab"
|
|
| 48 | + );
|
|
| 49 | + |
|
| 50 | + await BrowserTestUtils.synthesizeMouseAtCenter(
|
|
| 51 | + "a",
|
|
| 52 | + { button: 0, shiftKey: true },
|
|
| 53 | + browser
|
|
| 54 | + );
|
|
| 55 | + // This is fragile and might miss the new window, but the test will fail
|
|
| 56 | + // anyway when finishing with an extra window left behind.
|
|
| 57 | + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
|
| 58 | + await new Promise(resolve => setTimeout(resolve, 200));
|
|
| 59 | + is(
|
|
| 60 | + BrowserWindowTracker.windowCount,
|
|
| 61 | + 1,
|
|
| 62 | + "Shift+click on javascript: link shouldn't open a new window"
|
|
| 63 | + );
|
|
| 64 | + }
|
|
| 65 | + );
|
|
| 66 | +});
|
|
| 67 | + |
|
| 68 | +add_task(async function iframe_link() {
|
|
| 69 | + await BrowserTestUtils.withNewTab(
|
|
| 70 | + `data:text/html,<iframe src="${IFRAME_PATH}"></iframe>`,
|
|
| 71 | + async browser => {
|
|
| 72 | + // ctrl/cmd-click the link in the subframe.
|
|
| 73 | + await BrowserTestUtils.synthesizeMouseAtCenter(
|
|
| 74 | + "a",
|
|
| 75 | + { ctrlKey: true, metaKey: true },
|
|
| 76 | + browser.browsingContext.children[0]
|
|
| 77 | + );
|
|
| 78 | + |
|
| 79 | + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
|
| 80 | + await new Promise(resolve => setTimeout(resolve, 200));
|
|
| 81 | + is(
|
|
| 82 | + gBrowser.tabs.length,
|
|
| 83 | + 2,
|
|
| 84 | + "Click on javascript: link in iframe shouldn't open a new tab"
|
|
| 85 | + );
|
|
| 86 | + }
|
|
| 87 | + );
|
|
| 88 | +}); |
| 1 | +<!DOCTYPE html>
|
|
| 2 | +<a href="javascript:alert(1)">click me |
| ... | ... | @@ -73,6 +73,7 @@ |
| 73 | 73 | #include "mozilla/PresShell.h"
|
| 74 | 74 | #include "mozilla/ProfilerLabels.h"
|
| 75 | 75 | #include "mozilla/StaticPrefs_browser.h"
|
| 76 | +#include "mozilla/StaticPrefs_dom.h"
|
|
| 76 | 77 | #include "nsChannelClassifier.h"
|
| 77 | 78 | #include "nsFocusManager.h"
|
| 78 | 79 | #include "ReferrerInfo.h"
|
| ... | ... | @@ -736,11 +737,12 @@ nsObjectLoadingContent::UpdateObjectParameters() { |
| 736 | 737 | /// Codebase
|
| 737 | 738 | ///
|
| 738 | 739 | |
| 739 | - nsAutoString codebaseStr;
|
|
| 740 | 740 | nsIURI* docBaseURI = el->GetBaseURI();
|
| 741 | - el->GetAttr(nsGkAtoms::codebase, codebaseStr);
|
|
| 742 | 741 | |
| 743 | - if (!codebaseStr.IsEmpty()) {
|
|
| 742 | + nsAutoString codebaseStr;
|
|
| 743 | + el->GetAttr(nsGkAtoms::codebase, codebaseStr);
|
|
| 744 | + if (StaticPrefs::dom_object_embed_codebase_enabled() &&
|
|
| 745 | + !codebaseStr.IsEmpty()) {
|
|
| 744 | 746 | rv = nsContentUtils::NewURIWithDocumentCharset(
|
| 745 | 747 | getter_AddRefs(newBaseURI), codebaseStr, el->OwnerDoc(), docBaseURI);
|
| 746 | 748 | if (NS_FAILED(rv)) {
|
| ... | ... | @@ -3633,6 +3633,12 @@ |
| 3633 | 3633 | value: true
|
| 3634 | 3634 | mirror: always
|
| 3635 | 3635 | |
| 3636 | +# Whether the codebase attribute in an <object> is used as the base URI.
|
|
| 3637 | +- name: dom.object_embed.codebase.enabled
|
|
| 3638 | + type: bool
|
|
| 3639 | + value: false
|
|
| 3640 | + mirror: always
|
|
| 3641 | + |
|
| 3636 | 3642 | # Whether origin trials are enabled.
|
| 3637 | 3643 | - name: dom.origin-trials.enabled
|
| 3638 | 3644 | type: bool
|
| ... | ... | @@ -30,4 +30,17 @@ async_test(t => { |
| 30 | 30 | obj.onerror = t.unreached_func();
|
| 31 | 31 | document.body.appendChild(obj);
|
| 32 | 32 | }, "object's typemustmatch content attribute should not be supported");
|
| 33 | + |
|
| 34 | +async_test(t => {
|
|
| 35 | + const obj = document.createElement("object");
|
|
| 36 | + t.add_cleanup(() => obj.remove());
|
|
| 37 | + obj.setAttribute("data", "/common/blank.html");
|
|
| 38 | + obj.setAttribute("codebase", "https://test.invalid/");
|
|
| 39 | + obj.onload = t.step_func_done(() => {
|
|
| 40 | + assert_not_equals(obj.contentDocument, null, "/common/blank.html should be loaded");
|
|
| 41 | + assert_equals(obj.contentDocument.location.origin, location.origin, "document should be loaded with current origin as base");
|
|
| 42 | + });
|
|
| 43 | + obj.onerror = t.unreached_func();
|
|
| 44 | + document.body.appendChild(obj);
|
|
| 45 | +}, "object's codebase content attribute should not be supported");
|
|
| 33 | 46 | </script> |
| ... | ... | @@ -66,6 +66,10 @@ static const char kHTMLMarkupPrefix[] = |
| 66 | 66 | |
| 67 | 67 | static const char kURIListMime[] = "text/uri-list";
|
| 68 | 68 | |
| 69 | +// MIME to exclude sensitive data (password) from the clipboard history on not
|
|
| 70 | +// just KDE.
|
|
| 71 | +static const char kKDEPasswordManagerHintMime[] = "x-kde-passwordManagerHint";
|
|
| 72 | + |
|
| 69 | 73 | MOZ_CONSTINIT ClipboardTargets nsRetrievalContext::sClipboardTargets;
|
| 70 | 74 | MOZ_CONSTINIT ClipboardTargets nsRetrievalContext::sPrimaryTargets;
|
| 71 | 75 | |
| ... | ... | @@ -313,6 +317,12 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, |
| 313 | 317 | gtk_target_list_add(list, atom, 0, 0);
|
| 314 | 318 | }
|
| 315 | 319 | |
| 320 | + // Try to exclude private data from clipboard history.
|
|
| 321 | + if (aTransferable->GetIsPrivateData()) {
|
|
| 322 | + GdkAtom atom = gdk_atom_intern(kKDEPasswordManagerHintMime, FALSE);
|
|
| 323 | + gtk_target_list_add(list, atom, 0, 0);
|
|
| 324 | + }
|
|
| 325 | + |
|
| 316 | 326 | // Get GTK clipboard (CLIPBOARD or PRIMARY)
|
| 317 | 327 | GtkClipboard* gtkClipboard =
|
| 318 | 328 | gtk_clipboard_get(GetSelectionAtom(aWhichClipboard));
|
| ... | ... | @@ -1228,6 +1238,22 @@ void nsClipboard::SelectionGetEvent(GtkClipboard* aClipboard, |
| 1228 | 1238 | return;
|
| 1229 | 1239 | }
|
| 1230 | 1240 | |
| 1241 | + if (selectionTarget == gdk_atom_intern(kKDEPasswordManagerHintMime, FALSE)) {
|
|
| 1242 | + if (!trans->GetIsPrivateData()) {
|
|
| 1243 | + MOZ_CLIPBOARD_LOG(
|
|
| 1244 | + " requested %s, but the data isn't actually private!\n",
|
|
| 1245 | + kKDEPasswordManagerHintMime);
|
|
| 1246 | + return;
|
|
| 1247 | + }
|
|
| 1248 | + |
|
| 1249 | + static const char* kSecret = "secret";
|
|
| 1250 | + MOZ_CLIPBOARD_LOG(" Setting data to '%s' for %s\n", kSecret,
|
|
| 1251 | + kKDEPasswordManagerHintMime);
|
|
| 1252 | + gtk_selection_data_set(aSelectionData, selectionTarget, 8,
|
|
| 1253 | + (const guchar*)kSecret, strlen(kSecret));
|
|
| 1254 | + return;
|
|
| 1255 | + }
|
|
| 1256 | + |
|
| 1231 | 1257 | MOZ_CLIPBOARD_LOG(" Try if we have anything at GetTransferData() for %s\n",
|
| 1232 | 1258 | GUniquePtr<gchar>(gdk_atom_name(selectionTarget)).get());
|
| 1233 | 1259 |