Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
EveryWindow: "resource:///modules/EveryWindow.sys.mjs",
});
const NOTIFICATION_VALUE = "unexpected-script-notification";
export let UnexpectedScriptObserver = {
// EveryWindow has a race condition in early startup where a callback may be called twice
// for the same window. This WeakSet is used to track which windows have already been
_windowsHandled: new WeakSet(),
_notificationHasBeenShown: false,
async observe(aSubject, aTopic, aScriptName) {
if (
aTopic != "UnexpectedJavaScriptLoad-Live" &&
aTopic != "UnexpectedJavaScriptLoad-ResetNotification" &&
aTopic != "UnexpectedJavaScriptLoad-UserTookAction"
) {
return;
}
if (aTopic == "UnexpectedJavaScriptLoad-ResetNotification") {
this._notificationHasBeenShown = false;
this._windowsHandled = new WeakSet();
return;
}
if (aTopic == "UnexpectedJavaScriptLoad-UserTookAction") {
lazy.EveryWindow.unregisterCallback("UnexpectedScriptLoadPanel");
return;
}
if (
Services.prefs.getBoolPref(
"security.hide_parent_unrestricted_js_loads_warning.temporary",
false
)
) {
return;
}
if (this._notificationHasBeenShown) {
// There is already a notification bar, or we showed one in the past and we
// won't show it again until browser restart
return;
}
GleanPings.unexpectedScriptLoad.setEnabled(true);
let scriptOrigin;
try {
let scriptUrl = new URL(aScriptName);
scriptOrigin = scriptUrl.hostname;
if (scriptUrl.protocol != "http:" && scriptUrl.protocol != "https:") {
// For this dialog, we only care about loading scripts from web origins
return;
}
} catch (e) {
console.error("Invalid scriptName URL:", aScriptName);
// For this dialog, we only care about loading scripts from web origins,
// so if we couldn't parse it, just exit.
return;
}
lazy.EveryWindow.registerCallback(
"UnexpectedScriptLoadPanel",
async window => {
if (this._windowsHandled.has(window)) {
return;
}
this._windowsHandled.add(window);
let MozXULElement = window.MozXULElement;
let document = window.document;
MozXULElement.insertFTLIfNeeded("browser/unexpectedScript.ftl");
let messageFragment = document.createDocumentFragment();
let message = document.createElement("span");
document.l10n.setAttributes(message, "unexpected-script-load-message", {
origin: scriptOrigin,
});
messageFragment.appendChild(message);
// ----------------------------------------------------------------
let openWindow = action => {
let args = {
action,
scriptName: aScriptName,
};
window.gDialogBox.open(
"chrome://browser/content/security/unexpectedScriptLoad.xhtml",
args
);
};
// ----------------------------------------------------------------
let buttons = [
{
supportPage: "unexpected-script-load",
callback: () => {
Glean.unexpectedScriptLoad.moreInfoOpened.record();
},
},
];
buttons.push({
"l10n-id": "unexpected-script-load-message-button-allow",
callback: () => {
openWindow("allow");
return true;
},
});
buttons.push({
"l10n-id": "unexpected-script-load-message-button-block",
callback: () => {
openWindow("block");
return true; // Do not close the dialog bar until the user has done so explcitly or taken an action
},
});
let notificationBox = window.gNotificationBox;
if (!notificationBox.getNotificationWithValue(NOTIFICATION_VALUE)) {
await notificationBox.appendNotification(
NOTIFICATION_VALUE,
{
label: messageFragment,
priority: notificationBox.PRIORITY_WARNING_HIGH,
eventCallback: event => {
if (event == "dismissed") {
Glean.unexpectedScriptLoad.infobarDismissed.record();
GleanPings.unexpectedScriptLoad.submit();
}
},
},
buttons
);
}
},
// Unregister Callback:
// This is needed to remove the notification bar from all the windows
// once the user has taken action on one of them, and ensure any open
// dialog box is also closed.
async window => {
window.gNotificationBox
.getNotificationWithValue(NOTIFICATION_VALUE)
?.close();
if (
window.gDialogBox?.dialog?._openedURL ==
"chrome://browser/content/security/unexpectedScriptLoad.xhtml"
) {
window.gDialogBox.dialog.close();
}
GleanPings.unexpectedScriptLoad.submit();
}
);
Glean.unexpectedScriptLoad.infobarShown.record();
this._notificationHasBeenShown = true;
},
};