Commits:
-
1e27e250
by Tom Schuster at 2025-08-17T23:24:32+02:00
Bug 672618 - Don't execute _javascript_: URLs on CTRL+click, middle-click etc. r=dao
Differential Revision: https://phabricator.services.mozilla.com/D256648
-
15852030
by Tom Schuster at 2025-08-17T23:33:51+02:00
Bug 1701974 - Use x-kde-passwordManagerHint when copying private data to the clipboard. r=stransky
Differential Revision: https://phabricator.services.mozilla.com/D256781
-
1fcba6b6
by Tom Schuster at 2025-08-18T10:13:32+02:00
Bug 1973900 - Remove support for the codebase attribute from <object>. r=farre,dom-core
Differential Revision: https://phabricator.services.mozilla.com/D254958
11 changed files:
Changes:
browser/actors/ClickHandlerChild.sys.mjs
| ... |
... |
@@ -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,
|
browser/app/profile/firefox.js
| ... |
... |
@@ -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);
|
browser/base/content/test/general/browser_modifiedclick_inherit_principal.js
| ... |
... |
@@ -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 () {
|
browser/base/content/test/linkHandling/browser.toml
| ... |
... |
@@ -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
|
+] |
browser/base/content/test/linkHandling/browser_contentAreaClick_subframe_javascript.js
| ... |
... |
@@ -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=""p">${gExampleComRoot + IFRAME_FILE}"></iframe>`,
|
|
10
|
14
|
async browser => {
|
browser/base/content/test/linkHandling/browser_javascript_links.js
|
|
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="">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=""p">${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
|
+}); |
browser/base/content/test/linkHandling/file_javascript_links_subframe.html
|
|
1
|
+<!DOCTYPE html>
|
|
|
2
|
+<a href="">"_javascript_:alert(1)">click me |
dom/base/nsObjectLoadingContent.cpp
| ... |
... |
@@ -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)) {
|
modules/libpref/init/StaticPrefList.yaml
| ... |
... |
@@ -3641,6 +3641,12 @@ |
|
3641
|
3641
|
value: true
|
|
3642
|
3642
|
mirror: always
|
|
3643
|
3643
|
|
|
|
3644
|
+# Whether the codebase attribute in an <object> is used as the base URI.
|
|
|
3645
|
+- name: dom.object_embed.codebase.enabled
|
|
|
3646
|
+ type: bool
|
|
|
3647
|
+ value: false
|
|
|
3648
|
+ mirror: always
|
|
|
3649
|
+
|
|
3644
|
3650
|
# Whether origin trials are enabled.
|
|
3645
|
3651
|
- name: dom.origin-trials.enabled
|
|
3646
|
3652
|
type: bool
|
testing/web-platform/tests/html/semantics/embedded-content/the-object-element/historical.html
| ... |
... |
@@ -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> |
widget/gtk/nsClipboard.cpp
| ... |
... |
@@ -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
|
|
|