Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • gk/tor-browser
  • peterstory/tor-browser
  • sanketh/tor-browser
  • acat/tor-browser
  • sysrqb/tor-browser
  • boklm/tor-browser
  • dan/tor-browser
  • fabrizio/tor-browser
  • victorvw/tor-browser
  • aguestuser/tor-browser
  • WofWca/tor-browser
  • p13dz/tor-browser
  • mwolfe/tor-browser
  • tpo/applications/tor-browser
  • brade/tor-browser
  • pierov/tor-browser
  • ma1/tor-browser
  • JeremyRand/tor-browser
  • henry/tor-browser
  • msimonelli/tor-browser
  • cypherpunks1/tor-browser
  • blackZwork/tor-browser
  • starlingroot/tor-browser
  • cohosh/tor-browser
  • t-m-w/tor-browser
  • trinity-1686a/tor-browser
  • HHN/tor-browser
  • emmapeel/tor-browser
  • Achintya_Sharma/tor-browser
  • guest475646844/tor-browser
  • Mima/tor-browser
  • morgan/tor-browser
  • clairehurst/tor-browser
  • NoisyCoil/tor-browser
  • gus/tor-browser
  • Francewhoa/tor-browser
  • novialriptide/tor-browser
  • jwilde/tor-browser
  • brizental/tor-browser
  • ourhopeforfreedom/tor-browser
  • onyinyang/tor-browser
  • Noino/tor-browser
  • murmelurmel/tor-browser
43 results
Show changes
Showing
with 764 additions and 43 deletions
......@@ -151,7 +151,7 @@
hasicon="true"
hidden="true">
<popupnotificationcontent id="update-restart-notification-content" orient="vertical">
<description id="update-restart-description" data-lazy-l10n-id="appmenu-update-restart-message2"></description>
<description id="update-restart-description">&#160;</description>
</popupnotificationcontent>
</popupnotification>
......
......@@ -18,6 +18,8 @@ var { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
Downloads: "resource://gre/modules/Downloads.jsm",
......@@ -45,17 +47,18 @@ class DownloadSpamProtection {
return this.list;
}
update(url) {
update(url, principal) {
if (this._blockedURLToDownloadSpam.has(url)) {
let downloadSpam = this._blockedURLToDownloadSpam.get(url);
this.spamList.remove(downloadSpam);
downloadSpam.principal = principal;
downloadSpam.blockedDownloadsCount += 1;
this.spamList.add(downloadSpam);
this._indicator.onDownloadStateChanged(downloadSpam);
return;
}
let downloadSpam = new DownloadSpam(url);
let downloadSpam = new DownloadSpam(url, principal, this);
this.spamList.add(downloadSpam);
this._blockedURLToDownloadSpam.set(url, downloadSpam);
let hasActiveDownloads = DownloadsCommon.summarizeDownloads(
......@@ -85,8 +88,10 @@ class DownloadSpamProtection {
* @extends Download
*/
class DownloadSpam extends Download {
constructor(url) {
constructor(url, principal, protectionController) {
super();
this.protectionController = protectionController;
this.principal = principal.QueryInterface(Ci.nsIPrincipal);
this.hasBlockedData = true;
this.stopped = true;
this.error = new DownloadError({
......@@ -97,4 +102,16 @@ class DownloadSpam extends Download {
this.source = { url };
this.blockedDownloadsCount = 1;
}
allow() {
const pm = Services.perms;
pm.addFromPrincipal(
this.principal,
"automatic-download",
pm.ALLOW_ACTION,
pm.EXPIRE_SESSION
);
this.hasBlockedData = this.hasPartialData = false;
this.protectionController.clearDownloadSpam(this.source.url);
this._notifyChange();
}
}
......@@ -193,6 +193,10 @@ this.browserAction = class extends ExtensionAPIPersistent {
}
build() {
// The extension ID for NoScript (WebExtension)
const isNoScript =
this.extension.id === "{73a6fe31-595d-460b-a920-fcc0f8843232}";
let widget = CustomizableUI.createWidget({
id: this.id,
viewId: this.viewId,
......@@ -200,7 +204,11 @@ this.browserAction = class extends ExtensionAPIPersistent {
removable: true,
label: this.action.getProperty(null, "title"),
tooltiptext: this.action.getProperty(null, "title"),
defaultArea: browserAreas[this.action.getDefaultArea()],
// Do not want to add the NoScript extension to the toolbar by default.
// tor-browser#41736
defaultArea: isNoScript
? null
: browserAreas[this.action.getDefaultArea()],
showInPrivateBrowsing: this.extension.privateBrowsingAllowed,
// Don't attempt to load properties from the built-in widget string
......
......@@ -38,19 +38,18 @@ DIRS += [
"extensions",
"pagedata",
"migration",
"newidentity",
"newtab",
"originattributes",
"ion",
"places",
"pocket",
"preferences",
"privatebrowsing",
"prompts",
"protections",
"protocolhandler",
"resistfingerprinting",
"screenshots",
"search",
"securitylevel",
"sessionstore",
"shell",
"syncedtabs",
......@@ -65,7 +64,6 @@ DIRS += ["build"]
if CONFIG["NIGHTLY_BUILD"]:
DIRS += [
"colorways",
"firefoxview",
]
......
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#infoTitle {
font-weight: 600;
}
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
document.addEventListener("dialogaccept", () => {
const retvals = window.arguments[0];
retvals.confirmed = true;
retvals.neverAskAgain = document.querySelector("#neverAskAgain").checked;
});
document.addEventListener("DOMContentLoaded", () => {
const { NewIdentityStrings } = window.arguments[0];
const dialog = document.querySelector("#newIdentityDialog");
dialog.querySelector("#infoTitle").textContent =
NewIdentityStrings.new_identity_prompt_title;
dialog.querySelector("#infoBody").textContent =
NewIdentityStrings.new_identity_prompt;
dialog.querySelector("#neverAskAgain").label =
NewIdentityStrings.new_identity_ask_again;
const accept = dialog.getButton("accept");
accept.label = NewIdentityStrings.new_identity_restart;
accept.classList.add("danger-button");
});
<?xml version="1.0"?>
<!-- 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
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!-- based on resetProfile.xhtml -->
<?xml-stylesheet href="chrome://global/skin/global.css"?>
<?xml-stylesheet href="chrome://global/content/commonDialog.css"?>
<?xml-stylesheet href="chrome://global/skin/commonDialog.css"?>
<?xml-stylesheet href="chrome://browser/content/newIdentityDialog.css"?>
<window id="newIdentityDialogWindow"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
aria-describedby="infoBody">
<dialog id="newIdentityDialog"
buttons="accept,cancel"
defaultButton="accept">
<linkset>
<!-- Without this document.l10n is not initialized, and we need it for the
cancel button. -->
<html:link rel="localization" href="branding/brand.ftl"/>
</linkset>
<div xmlns="http://www.w3.org/1999/xhtml">
<div id="dialogGrid">
<div class="dialogRow" id="infoRow">
<div id="iconContainer">
<xul:image id="infoIcon"/>
</div>
<div id="infoContainer">
<xul:description id="infoTitle"/>
<xul:description id="infoBody" context="contentAreaContextMenu" noinitialfocus="true"/>
<xul:checkbox id="neverAskAgain"/>
</div>
</div>
</div>
</div>
<script src="chrome://browser/content/newIdentityDialog.js"/>
</dialog>
</window>
"use strict";
var EXPORTED_SYMBOLS = ["NewIdentityButton"];
/* globals CustomizableUI Services gFindBarInitialized gFindBar
OpenBrowserWindow PrivateBrowsingUtils XPCOMUtils
*/
XPCOMUtils.defineLazyGetter(this, "NewIdentityStrings", () => {
const brandBundle = Services.strings.createBundle(
"chrome://branding/locale/brand.properties"
);
const brandShortName = brandBundle.GetStringFromName("brandShortName");
let strings = {
new_identity: "New Identity",
new_identity_sentence_case: "New identity",
new_identity_prompt_title: "Reset your identity?",
new_identity_prompt: `${brandShortName} will close all windows and tabs. All website sessions will be lost. \nRestart ${brandShortName} now to reset your identity?`,
new_identity_restart: `Restart ${brandShortName}`,
new_identity_ask_again: "Never ask me again",
new_identity_menu_accesskey: "I",
};
let bundle = null;
try {
bundle = Services.strings.createBundle(
"chrome://browser/locale/newIdentity.properties"
);
} catch (e) {
console.warn("Could not load the New Identity strings");
}
if (bundle) {
for (const key of Object.keys(strings)) {
try {
strings[key] = bundle.GetStringFromName(key);
} catch (e) {}
}
strings.new_identity_prompt = strings.new_identity_prompt.replaceAll(
"%S",
brandShortName
);
strings.new_identity_restart = strings.new_identity_restart.replaceAll(
"%S",
brandShortName
);
}
return strings;
});
// Use a lazy getter because NewIdentityButton is declared more than once
// otherwise.
XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
// Logger adapted from CustomizableUI.jsm
const logger = (() => {
const { ConsoleAPI } = ChromeUtils.import(
"resource://gre/modules/Console.jsm"
);
const consoleOptions = {
maxLogLevel: "info",
maxLogLevelPref: "browser.new_identity.log_level",
prefix: "NewIdentity",
};
return new ConsoleAPI(consoleOptions);
})();
const topics = Object.freeze({
newIdentityRequested: "new-identity-requested",
});
class NewIdentityImpl {
async run() {
this.disableAllJS();
await this.clearState();
await this.openNewWindow();
this.closeOldWindow();
this.broadcast();
}
// Disable JS (as a defense-in-depth measure)
disableAllJS() {
logger.info("Disabling JavaScript");
const enumerator = Services.wm.getEnumerator("navigator:browser");
while (enumerator.hasMoreElements()) {
const win = enumerator.getNext();
this.disableWindowJS(win);
}
}
disableWindowJS(win) {
const browsers = win.gBrowser?.browsers || [];
for (const browser of browsers) {
if (!browser) {
continue;
}
this.disableBrowserJS(browser);
try {
browser.webNavigation?.stop(browser.webNavigation.STOP_ALL);
} catch (e) {
logger.warn("Could not stop navigation", e, browser.currentURI);
}
}
}
disableBrowserJS(browser) {
if (!browser) {
return;
}
// Does the following still apply?
// Solution from: https://bugzilla.mozilla.org/show_bug.cgi?id=409737
// XXX: This kills the entire window. We need to redirect
// focus and inform the user via a lightbox.
const eventSuppressor = browser.contentWindow?.windowUtils;
if (browser.browsingContext) {
browser.browsingContext.allowJavascript = false;
}
try {
// My estimation is that this does not get the inner iframe windows,
// but that does not matter, because iframes should be destroyed
// on the next load.
// Should we log when browser.contentWindow is null?
if (browser.contentWindow) {
browser.contentWindow.name = null;
browser.contentWindow.window.name = null;
}
} catch (e) {
logger.warn("Failed to reset window.name", e);
}
eventSuppressor?.suppressEventHandling(true);
}
// Clear state
async clearState() {
logger.info("Clearing the state");
this.closeTabs();
this.clearSearchBar();
this.clearPrivateSessionHistory();
this.clearHTTPAuths();
this.clearCryptoTokens();
this.clearOCSPCache();
this.clearSecuritySettings();
this.clearImageCaches();
this.clearStorage();
this.clearPreferencesAndPermissions();
await this.clearData();
this.clearConnections();
this.clearPrivateSession();
}
clearSiteSpecificZoom() {
Services.prefs.setBoolPref(
"browser.zoom.siteSpecific",
!Services.prefs.getBoolPref("browser.zoom.siteSpecific")
);
Services.prefs.setBoolPref(
"browser.zoom.siteSpecific",
!Services.prefs.getBoolPref("browser.zoom.siteSpecific")
);
}
closeTabs() {
logger.info("Closing tabs");
if (
!Services.prefs.getBoolPref("browser.new_identity.close_newnym", true)
) {
logger.info("Not closing tabs");
return;
}
// TODO: muck around with browser.tabs.warnOnClose.. maybe..
logger.info("Closing tabs...");
const enumerator = Services.wm.getEnumerator("navigator:browser");
const windowsToClose = [];
while (enumerator.hasMoreElements()) {
const win = enumerator.getNext();
const browser = win.gBrowser;
if (!browser) {
logger.warn("No browser for possible window to close");
continue;
}
const tabsToRemove = [];
for (const b of browser.browsers) {
const tab = browser.getTabForBrowser(b);
if (tab) {
tabsToRemove.push(tab);
} else {
logger.warn("Browser has a null tab", b);
}
}
if (win == window) {
browser.addWebTab("about:blank");
} else {
// It is a bad idea to alter the window list while iterating
// over it, so add this window to an array and close it later.
windowsToClose.push(win);
}
// Close each tab except the new blank one that we created.
tabsToRemove.forEach(aTab => browser.removeTab(aTab));
}
// Close all XUL windows except this one.
logger.info("Closing windows...");
windowsToClose.forEach(aWin => aWin.close());
logger.info("Closed all tabs");
// This clears the undo tab history.
const tabs = Services.prefs.getIntPref(
"browser.sessionstore.max_tabs_undo"
);
Services.prefs.setIntPref("browser.sessionstore.max_tabs_undo", 0);
Services.prefs.setIntPref("browser.sessionstore.max_tabs_undo", tabs);
}
clearSearchBar() {
logger.info("Clearing searchbox");
// Bug #10800: Trying to clear search/find can cause exceptions
// in unknown cases. Just log for now.
try {
const searchBar = window.document.getElementById("searchbar");
if (searchBar) {
searchBar.textbox.reset();
}
} catch (e) {
logger.error("Exception on clearing search box", e);
}
try {
if (gFindBarInitialized) {
const findbox = gFindBar.getElement("findbar-textbox");
findbox.reset();
gFindBar.close();
}
} catch (e) {
logger.error("Exception on clearing find bar", e);
}
}
clearPrivateSessionHistory() {
logger.info("Emitting Private Browsing Session clear event");
Services.obs.notifyObservers(null, "browser:purge-session-history");
}
clearHTTPAuths() {
if (
!Services.prefs.getBoolPref(
"browser.new_identity.clear_http_auth",
true
)
) {
logger.info("Skipping HTTP Auths, because disabled");
return;
}
logger.info("Clearing HTTP Auths");
const auth = Cc["@mozilla.org/network/http-auth-manager;1"].getService(
Ci.nsIHttpAuthManager
);
auth.clearAll();
}
clearCryptoTokens() {
logger.info("Clearing Crypto Tokens");
// Clear all crypto auth tokens. This includes calls to PK11_LogoutAll(),
// nsNSSComponent::LogoutAuthenticatedPK11() and clearing the SSL session
// cache.
const sdr = Cc["@mozilla.org/security/sdr;1"].getService(
Ci.nsISecretDecoderRing
);
sdr.logoutAndTeardown();
}
clearOCSPCache() {
// nsNSSComponent::Observe() watches security.OCSP.enabled, which calls
// setValidationOptions(), which in turn calls setNonPkixOcspEnabled() which,
// if security.OCSP.enabled is set to 0, calls CERT_DisableOCSPChecking(),
// which calls CERT_ClearOCSPCache().
// See: https://mxr.mozilla.org/comm-esr24/source/mozilla/security/manager/ssl/src/nsNSSComponent.cpp
const ocsp = Services.prefs.getIntPref("security.OCSP.enabled");
Services.prefs.setIntPref("security.OCSP.enabled", 0);
Services.prefs.setIntPref("security.OCSP.enabled", ocsp);
}
clearSecuritySettings() {
// Clear site security settings
const sss = Cc["@mozilla.org/ssservice;1"].getService(
Ci.nsISiteSecurityService
);
sss.clearAll();
}
clearImageCaches() {
logger.info("Clearing Image Cache");
// In Firefox 18 and newer, there are two image caches: one that is used
// for regular browsing, and one that is used for private browsing.
this.clearImageCacheRB();
this.clearImageCachePB();
}
clearImageCacheRB() {
try {
const imgTools = Cc["@mozilla.org/image/tools;1"].getService(
Ci.imgITools
);
const imgCache = imgTools.getImgCacheForDocument(null);
// Evict all but chrome cache
imgCache.clearCache(false);
} catch (e) {
// FIXME: This can happen in some rare cases involving XULish image data
// in combination with our image cache isolation patch. Sure isn't
// a good thing, but it's not really a super-cookie vector either.
// We should fix it eventually.
logger.error("Exception on image cache clearing", e);
}
}
clearImageCachePB() {
const imgTools = Cc["@mozilla.org/image/tools;1"].getService(
Ci.imgITools
);
try {
// Try to clear the private browsing cache. To do so, we must locate a
// content document that is contained within a private browsing window.
let didClearPBCache = false;
const enumerator = Services.wm.getEnumerator("navigator:browser");
while (!didClearPBCache && enumerator.hasMoreElements()) {
const win = enumerator.getNext();
let browserDoc = win.document.documentElement;
if (!browserDoc.hasAttribute("privatebrowsingmode")) {
continue;
}
const tabbrowser = win.gBrowser;
if (!tabbrowser) {
continue;
}
for (const browser of tabbrowser.browsers) {
const doc = browser.contentDocument;
if (doc) {
const imgCache = imgTools.getImgCacheForDocument(doc);
// Evict all but chrome cache
imgCache.clearCache(false);
didClearPBCache = true;
break;
}
}
}
} catch (e) {
logger.error("Exception on private browsing image cache clearing", e);
}
}
clearStorage() {
logger.info("Clearing Disk and Memory Caches");
try {
Services.cache2.clear();
} catch (e) {
logger.error("Exception on cache clearing", e);
}
logger.info("Clearing Cookies and DOM Storage");
Services.cookies.removeAll();
}
clearPreferencesAndPermissions() {
logger.info("Clearing Content Preferences");
ChromeUtils.defineModuleGetter(
this,
"PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm"
);
const pbCtxt = PrivateBrowsingUtils.privacyContextFromWindow(window);
const cps = Cc["@mozilla.org/content-pref/service;1"].getService(
Ci.nsIContentPrefService2
);
cps.removeAllDomains(pbCtxt);
this.clearSiteSpecificZoom();
logger.info("Clearing permissions");
try {
Services.perms.removeAll();
} catch (e) {
// Actually, this catch does not appear to be needed. Leaving it in for
// safety though.
logger.error("Cannot clear permissions", e);
}
logger.info("Syncing prefs");
// Force prefs to be synced to disk
Services.prefs.savePrefFile(null);
}
async clearData() {
logger.info("Calling the clearDataService");
const flags =
Services.clearData.CLEAR_ALL ^ Services.clearData.CLEAR_PASSWORDS;
return new Promise(resolve => {
Services.clearData.deleteData(flags, {
onDataDeleted(code) {
if (code !== Cr.NS_OK) {
logger.error(`Error while calling the clearDataService: ${code}`);
}
// We always resolve, because we do not want to interrupt the new
// identity procedure.
resolve();
},
});
});
}
clearConnections() {
logger.info("Closing open connections");
// Clear keep-alive
Services.obs.notifyObservers(this, "net:prune-all-connections");
}
clearPrivateSession() {
logger.info("Ending any remaining private browsing sessions.");
Services.obs.notifyObservers(null, "last-pb-context-exited");
}
// Broadcast as a hook to clear other data
broadcast() {
logger.info("Broadcasting the new identity");
Services.obs.notifyObservers({}, topics.newIdentityRequested);
}
// Window management
openNewWindow() {
logger.info("Opening a new window");
return new Promise(resolve => {
// Open a new window with the default homepage
// We could pass {private: true} but we do not because we enforce
// browser.privatebrowsing.autostart = true.
// What about users that change settings?
const win = OpenBrowserWindow();
// This mechanism to know when the new window is ready is used by
// OpenBrowserWindow itself (see its definition in browser.js).
win.addEventListener("MozAfterPaint", () => resolve(), { once: true });
});
}
closeOldWindow() {
logger.info("Closing the old window");
// Run garbage collection and cycle collection after window is gone.
// This ensures that blob URIs are forgotten.
window.addEventListener("unload", function(event) {
logger.debug("Initiating New Identity GC pass");
// Clear out potential pending sInterSliceGCTimer:
window.windowUtils.runNextCollectorTimer();
// Clear out potential pending sICCTimer:
window.windowUtils.runNextCollectorTimer();
// Schedule a garbage collection in 4000-1000ms...
window.windowUtils.garbageCollect();
// To ensure the GC runs immediately instead of 4-10s from now, we need
// to poke it at least 11 times.
// We need 5 pokes for GC, 1 poke for the interSliceGC, and 5 pokes for
// CC.
// See nsJSContext::RunNextCollectorTimer() in
// https://mxr.mozilla.org/mozilla-central/source/dom/base/nsJSEnvironment.cpp#1970.
// XXX: We might want to make our own method for immediate full GC...
for (let poke = 0; poke < 11; poke++) {
window.windowUtils.runNextCollectorTimer();
}
// And now, since the GC probably actually ran *after* the CC last time,
// run the whole thing again.
window.windowUtils.garbageCollect();
for (let poke = 0; poke < 11; poke++) {
window.windowUtils.runNextCollectorTimer();
}
logger.debug("Completed New Identity GC pass");
});
// Close the current window for added safety
window.close();
}
}
let newIdentityInProgress = false;
return {
topics,
init() {
// We first search in the DOM for the identity button. If it does not
// exist it may be in the toolbox palette. In the latter case we still
// need to initialize the button in case it is added back later through
// customization.
const button =
document.getElementById("new-identity-button") ||
window.gNavToolbox.palette.querySelector("#new-identity-button");
if (button) {
button.setAttribute("tooltiptext", NewIdentityStrings.new_identity);
// Include an equal label, shown in the overflow menu or during
// customization.
button.setAttribute("label", NewIdentityStrings.new_identity);
button.addEventListener("command", () => {
this.onCommand();
});
}
const viewCache = document.getElementById("appMenu-viewCache").content;
const appButton = viewCache.querySelector("#appMenu-new-identity");
if (appButton) {
appButton.setAttribute(
"label",
NewIdentityStrings.new_identity_sentence_case
);
appButton.addEventListener("command", () => {
this.onCommand();
});
}
const menu = document.querySelector("#menu_newIdentity");
if (menu) {
menu.setAttribute("label", NewIdentityStrings.new_identity);
menu.setAttribute(
"accesskey",
NewIdentityStrings.new_identity_menu_accesskey
);
menu.addEventListener("command", () => {
this.onCommand();
});
}
},
uninit() {},
async onCommand() {
try {
// Ignore if there's a New Identity in progress to avoid race
// conditions leading to failures (see bug 11783 for an example).
if (newIdentityInProgress) {
return;
}
newIdentityInProgress = true;
const prefConfirm = "browser.new_identity.confirm_newnym";
const shouldConfirm = Services.prefs.getBoolPref(prefConfirm, true);
if (shouldConfirm) {
const params = {
NewIdentityStrings,
confirmed: false,
neverAskAgain: false,
};
await window.gDialogBox.open(
"chrome://browser/content/newIdentityDialog.xhtml",
params
);
Services.prefs.setBoolPref(prefConfirm, !params.neverAskAgain);
if (!params.confirmed) {
return;
}
}
const impl = new NewIdentityImpl();
await impl.run();
} catch (e) {
// If something went wrong make sure we have the New Identity button
// enabled (again).
logger.error("Unexpected error", e);
window.alert("New Identity unexpected error: " + e);
} finally {
newIdentityInProgress = false;
}
},
};
});
browser.jar:
content/browser/newidentity.js (content/newidentity.js)
content/browser/newIdentityDialog.xhtml (content/newIdentityDialog.xhtml)
content/browser/newIdentityDialog.css (content/newIdentityDialog.css)
content/browser/newIdentityDialog.js (content/newIdentityDialog.js)
JAR_MANIFESTS += ["jar.mn"]
......@@ -420,20 +420,7 @@ class BaseAboutNewTabService {
* the newtab page has no effect on the result of this function.
*/
get defaultURL() {
// Generate the desired activity stream resource depending on state, e.g.,
// "resource://activity-stream/prerendered/activity-stream.html"
// "resource://activity-stream/prerendered/activity-stream-debug.html"
// "resource://activity-stream/prerendered/activity-stream-noscripts.html"
return [
"resource://activity-stream/prerendered/",
"activity-stream",
// Debug version loads dev scripts but noscripts separately loads scripts
this.activityStreamDebug && !this.privilegedAboutProcessEnabled
? "-debug"
: "",
this.privilegedAboutProcessEnabled ? "-noscripts" : "",
".html",
].join("");
return "about:blank";
}
get welcomeURL() {
......
......@@ -33,7 +33,6 @@
class="check-home-page-controlled"
data-preference-related="browser.startup.homepage">
<menupopup>
<menuitem value="0" data-l10n-id="home-mode-choice-default" />
<menuitem value="2" data-l10n-id="home-mode-choice-custom" />
<menuitem value="1" data-l10n-id="home-mode-choice-blank" />
</menupopup>
......@@ -84,7 +83,6 @@
Preferences so we need to handle setting the pref manually.-->
<menulist id="newTabMode" flex="1" data-preference-related="browser.newtabpage.enabled">
<menupopup>
<menuitem value="0" data-l10n-id="home-mode-choice-default" />
<menuitem value="1" data-l10n-id="home-mode-choice-blank" />
</menupopup>
</menulist>
......
......@@ -380,10 +380,14 @@ var gHomePane = {
if (controllingExtension && controllingExtension.id) {
newValue = controllingExtension.id;
} else if (isDefault) {
newValue = this.HOME_MODE_FIREFOX_HOME;
} else if (isBlank) {
// For base-browser, we want to check isBlank first since the default page
// is also the blank page, but we only have a menu option for
// HOME_MODE_BLANK, rather than HOME_MODE_FIREFOX_HOME.
// See tor-browser#41609.
newValue = this.HOME_MODE_BLANK;
} else if (isDefault) {
newValue = this.HOME_MODE_FIREFOX_HOME;
} else {
newValue = this.HOME_MODE_CUSTOM;
}
......
......@@ -322,7 +322,7 @@
</groupbox>
<!-- Languages -->
<groupbox id="languagesGroup" data-category="paneGeneral" hidden="true">
<groupbox id="languagesGroup" data-category="paneGeneral" hidden="true" data-subcategory="language">
<label><html:h2 data-l10n-id="language-header"/></label>
<vbox id="browserLanguagesBox" align="start" hidden="true">
......
......@@ -568,16 +568,10 @@ var gMainPane = {
.setAttribute("style", "display: none !important");
}
// Initialize the Firefox Updates section.
let version = AppConstants.MOZ_APP_VERSION_DISPLAY;
let version = AppConstants.BASE_BROWSER_VERSION;
// Include the build ID if this is an "a#" (nightly) build
if (/a\d+$/.test(version)) {
let buildID = Services.appinfo.appBuildID;
let year = buildID.slice(0, 4);
let month = buildID.slice(4, 6);
let day = buildID.slice(6, 8);
version += ` (${year}-${month}-${day})`;
}
// Base Browser and derivatives: do not include the build ID in our alphas,
// since they are not actually related to the build date.
// Append "(32-bit)" or "(64-bit)" build architecture to the version number:
let bundle = Services.strings.createBundle(
......@@ -1010,6 +1004,23 @@ var gMainPane = {
gMainPane.onPrimaryBrowserLanguageMenuChange(event);
});
// Temporary hack to cause the menu popup to resize itself just after being
// shown. See tor-browser#41371
// We get ~one frame of a potentially badly sized popup, and then the popup
// should re-adjust to the new size.
// TODO: Remove with firefox 115 since this is fixed properly in
// mozilla-central 107.
menulist.addEventListener("popupshown", () => {
const popupBox = menulist.menupopup;
// We change a layout parameter and then force a relayout. We choose
// "min-height: 0" since we expect this won't change the displayed result
// but is enough to force the relayout.
const minHeight = popupBox.style.minHeight;
popupBox.style.minHeight = 0;
popupBox.getBoundingClientRect();
popupBox.style.minHeight = minHeight;
});
gMainPane.updatePrimaryBrowserLanguageUI(Services.locale.appLocaleAsBCP47);
},
......@@ -1027,8 +1038,28 @@ var gMainPane = {
available,
{ preferNative: true }
);
let locales = available.map((code, i) => ({ code, name: localeNames[i] }));
locales.sort((a, b) => a.name > b.name);
let locales = available.map((code, i) => {
let name = localeNames[i].replace(/\s*\(.+\)$/g, "");
if (code === "ja-JP-macos") {
// Mozilla codebases handle Japanese in macOS in different ways,
// sometimes they call it ja-JP-mac and sometimes they call it
// ja-JP-macos. The former is translated to Japanese when specifying
// preferNative to true, the latter is not. Since seeing ja-JP-macos
// would be confusing anyway, we treat it as a special case.
// See tor-browser#41372 and Bug 1726586.
name =
Services.intl.getLocaleDisplayNames(undefined, ["ja"], {
preferNative: true,
})[0] + " (ja)";
} else {
name += ` (${code})`;
}
return {
code,
name,
};
});
locales.sort((a, b) => a.code.localeCompare(b.code));
let fragment = document.createDocumentFragment();
for (let { code, name } of locales) {
......
......@@ -460,6 +460,17 @@ async function scrollAndHighlight(subcategory, category) {
}
let header = getClosestDisplayedHeader(element);
// We assign a tabindex=-1 to the element so that we can focus it. This allows
// us to move screen reader's focus to an arbitrary position on the page.
// See tor-browser#41454 and bug 1799153.
element.setAttribute("tabindex", "-1");
// The element is not always immediately focusable, so we wait until the next
// loop.
setTimeout(() => {
Services.focus.setFocus(element, Services.focus.FLAG_NOSCROLL);
element.removeAttribute("tabindex");
});
scrollContentTo(header);
element.classList.add("spotlight");
}
......
......@@ -13,6 +13,7 @@
<?xml-stylesheet href="chrome://browser/skin/preferences/search.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/containers.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/privacy.css"?>
<?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelPreferences.css"?>
<!DOCTYPE html>
......
......@@ -1038,6 +1038,8 @@
<html:h1 data-l10n-id="security-header"/>
</hbox>
#include ../securitylevel/content/securityLevelPreferences.inc.xhtml
<!-- addons, forgery (phishing) UI Security -->
<groupbox id="browsingProtectionGroup" data-category="panePrivacy" hidden="true">
<label><html:h2 data-l10n-id="security-browsing-protection"/></label>
......
......@@ -48,6 +48,13 @@ XPCOMUtils.defineLazyGetter(this, "AlertsServiceDND", function() {
}
});
// TODO: module import via ChromeUtils.defineModuleGetter
XPCOMUtils.defineLazyScriptGetter(
this,
["SecurityLevelPreferences"],
"chrome://browser/content/securitylevel/securityLevel.js"
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"OS_AUTH_ENABLED",
......@@ -314,6 +321,16 @@ function initTCPRolloutSection() {
var gPrivacyPane = {
_pane: null,
/**
* Show the Security Level UI
*/
_initSecurityLevel() {
SecurityLevelPreferences.init();
window.addEventListener("unload", () => SecurityLevelPreferences.uninit(), {
once: true,
});
},
/**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
......@@ -523,6 +540,7 @@ var gPrivacyPane = {
this.trackingProtectionReadPrefs();
this.networkCookieBehaviorReadPrefs();
this._initTrackingProtectionExtensionControl();
this._initSecurityLevel();
Services.telemetry.setEventRecordingEnabled("pwmgr", true);
......
......@@ -82,7 +82,7 @@ async function test_dynamical_window_rounding(aWindow, aCheckFunc) {
// We need to wait for the updating the margins for the newly opened tab, or
// it will affect the following tests.
let promiseForTheFirstRounding = TestUtils.topicObserved(
"test:letterboxing:update-margin-finish"
"test:letterboxing:update-size-finish"
);
info("Open a content tab for testing.");
......@@ -108,7 +108,7 @@ async function test_dynamical_window_rounding(aWindow, aCheckFunc) {
let caseString = "Case " + width + "x" + height + ": ";
// Create a promise for waiting for the margin update.
let promiseRounding = TestUtils.topicObserved(
"test:letterboxing:update-margin-finish"
"test:letterboxing:update-size-finish"
);
let { containerWidth, containerHeight } = getContainerSize(tab);
......@@ -316,7 +316,7 @@ async function test_findbar(aWindow) {
);
let promiseRounding = TestUtils.topicObserved(
"test:letterboxing:update-margin-finish"
"test:letterboxing:update-size-finish"
);
let findBarOpenPromise = BrowserTestUtils.waitForEvent(
......@@ -330,7 +330,7 @@ async function test_findbar(aWindow) {
ok(true, "Margin updated when findbar opened");
promiseRounding = TestUtils.topicObserved(
"test:letterboxing:update-margin-finish"
"test:letterboxing:update-size-finish"
);
let findBarClosePromise = BrowserTestUtils.waitForEvent(
......