This is an automated email from the git hooks/post-receive script.
richard pushed a change to branch tor-browser-91.11.0esr-12.0-1 in repository tor-browser.
from ef0f0ae9f0e56 fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection new 0b894b41ed680 fixup! Bug 25658: Replace security slider with security level UI new c0426df7f7b37 Bug 40926: Implemented the New Identity feature
The 2 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "add" were already present in the repository and have only been added to this reference.
Summary of changes: browser/base/content/appmenu-viewcache.inc.xhtml | 12 +- browser/base/content/browser-menubar.inc | 5 +- browser/base/content/browser-sets.inc | 2 +- browser/base/content/browser.js | 10 + browser/base/content/browser.xhtml | 1 - browser/base/content/navigator-toolbox.inc.xhtml | 5 +- browser/components/moz.build | 1 + .../components/newidentity/content/newidentity.js | 566 +++++++++++++++++++++ browser/components/newidentity/jar.mn | 13 + .../locale/en-US/newIdentity.properties | 8 + .../{torpreferences => newidentity}/moz.build | 0 browser/components/preferences/preferences.xhtml | 1 - .../securitylevel/content/securityLevel.js | 146 +++++- .../content/securityLevelPanel.inc.xhtml | 7 +- .../content/securityLevelPreferences.inc.xhtml | 42 +- browser/components/securitylevel/jar.mn | 5 + .../locale/en-US/securityLevel.properties | 30 ++ browser/installer/package-manifest.in | 9 +- .../en-US/browser/base-browser/securityLevel.ftl | 66 --- 19 files changed, 797 insertions(+), 132 deletions(-) create mode 100644 browser/components/newidentity/content/newidentity.js create mode 100644 browser/components/newidentity/jar.mn create mode 100644 browser/components/newidentity/locale/en-US/newIdentity.properties copy browser/components/{torpreferences => newidentity}/moz.build (100%) create mode 100644 browser/components/securitylevel/locale/en-US/securityLevel.properties delete mode 100644 browser/locales/en-US/browser/base-browser/securityLevel.ftl
This is an automated email from the git hooks/post-receive script.
richard pushed a commit to branch tor-browser-91.11.0esr-12.0-1 in repository tor-browser.
commit 0b894b41ed680d08700cabb3497c94cef123281e Author: Pier Angelo Vendrame pierov@torproject.org AuthorDate: Wed Jul 13 11:00:16 2022 +0200
fixup! Bug 25658: Replace security slider with security level UI
Switched from Fluent to properties --- browser/base/content/browser.xhtml | 1 - browser/components/preferences/preferences.xhtml | 1 - .../securitylevel/content/securityLevel.js | 146 +++++++++++++++++++-- .../content/securityLevelPanel.inc.xhtml | 7 +- .../content/securityLevelPreferences.inc.xhtml | 42 +++--- browser/components/securitylevel/jar.mn | 5 + .../locale/en-US/securityLevel.properties | 30 +++++ browser/installer/package-manifest.in | 7 +- .../en-US/browser/base-browser/securityLevel.ftl | 66 ---------- 9 files changed, 190 insertions(+), 115 deletions(-)
diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 21af5188c18d2..394a464140186 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -85,7 +85,6 @@ <link rel="localization" href="browser/places.ftl"/> <link rel="localization" href="toolkit/printing/printUI.ftl"/> <link rel="localization" href="browser/tabbrowser.ftl"/> - <link rel="localization" href="browser/base-browser/securityLevel.ftl"/>
<title data-l10n-id="browser-main-window-title"></title>
diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml index 64a266a5756f5..30ce70079adb7 100644 --- a/browser/components/preferences/preferences.xhtml +++ b/browser/components/preferences/preferences.xhtml @@ -57,7 +57,6 @@ <link rel="localization" href="browser/preferences/siteDataSettings.ftl"/> <link rel="localization" href="browser/aboutDialog.ftl"/> <link rel="localization" href="browser/sanitize.ftl"/> - <link rel="localization" href="browser/base-browser/securityLevel.ftl"/> <link rel="localization" href="toolkit/updates/history.ftl"/> <link rel="localization" href="security/certificates/deviceManager.ftl"/> <link rel="localization" href="security/certificates/certManager.ftl"/> diff --git a/browser/components/securitylevel/content/securityLevel.js b/browser/components/securitylevel/content/securityLevel.js index 366814ac85666..dd54634472783 100644 --- a/browser/components/securitylevel/content/securityLevel.js +++ b/browser/components/securitylevel/content/securityLevel.js @@ -12,6 +12,64 @@ XPCOMUtils.defineLazyModuleGetters(this, {
const SecurityLevels = Object.freeze(["", "safest", "safer", "", "standard"]);
+XPCOMUtils.defineLazyGetter(this, "SecurityLevelStrings", () => { + let strings = { + // Generic terms + security_level: "Security Level", + security_level_standard: "Standard", + security_level_safer: "Safer", + security_level_safest: "Safest", + security_level_tooltip_standard: "Security Level: Standard", + security_level_tooltip_safer: "Security Level: Safer", + security_level_tooltip_safest: "Security Level: Safest", + // Shown only for custom level + security_level_custom: "Custom", + security_level_restore: "Restore Defaults", + security_level_learn_more: "Learn more", + // Panel + security_level_change: "Change…", + security_level_standard_summary: + "All Tor Browser and website features are enabled.", + security_level_safer_summary: + "Disables website features that are often dangerous, causing some sites to lose functionality.", + security_level_safest_summary: + "Only allows website features required for static sites and basic services. These changes affect images, media, and scripts.", + security_level_custom_summary: + "Your custom browser preferences have resulted in unusual security settings. For security and privacy reasons, we recommend you choose one of the default security levels.", + // Security level section in about:preferences#privacy + security_level_overview: + "Disable certain web features that can be used to attack your security and anonymity.", + security_level_list_safer: "At the safer setting:", + security_level_list_safest: "At the safest setting:", + // Strings for descriptions + security_level_js_https_only: "JavaScript is disabled on non-HTTPS sites.", + security_level_js_disabled: + "JavaScript is disabled by default on all sites.", + security_level_limit_typography: + "Some fonts and math symbols are disabled.", + security_level_limit_typography_svg: + "Some fonts, icons, math symbols, and images are disabled.", + security_level_limit_media: + "Audio and video (HTML5 media), and WebGL are click-to-play.", + }; + let bundle = null; + try { + bundle = Services.strings.createBundle( + "chrome://securitylevel/locale/securityLevel.properties" + ); + } catch (e) { + console.warn("Could not load the Security Level strings"); + } + if (bundle) { + for (const key of Object.keys(strings)) { + try { + strings[key] = bundle.GetStringFromName(key); + } catch (e) {} + } + } + return strings; +}); + /* Security Level Prefs
@@ -77,9 +135,9 @@ const SecurityLevelButton = { } const customStr = SecurityLevelPrefs.securityCustom ? "_custom" : ""; securityLevelButton.setAttribute("level", `${level}${customStr}`); - document.l10n.setAttributes( - securityLevelButton, - `security-level-button-${level}` + securityLevelButton.setAttribute( + "tooltiptext", + SecurityLevelStrings[`security_level_tooltip_${level}`] ); } }, @@ -199,6 +257,9 @@ const SecurityLevelPanel = { summary: "description#securityLevel-summary", restoreDefaults: "button#securityLevel-restoreDefaults", advancedSecuritySettings: "button#securityLevel-advancedSecuritySettings", + // Selectors used only for l10n - remove them when switching to Fluent + header: "#securityLevel-header", + learnMore: "#securityLevel-panel .learnMore", }),
_populateXUL() { @@ -214,7 +275,24 @@ const SecurityLevelPanel = { advancedSecuritySettings: document.querySelector( selectors.advancedSecuritySettings ), + header: document.querySelector(selectors.header), + learnMore: document.querySelector(selectors.learnMore), }; + + this._elements.header.textContent = SecurityLevelStrings.security_level; + this._elements.labelCustom.setAttribute( + "value", + SecurityLevelStrings.security_level_custom + ); + this._elements.learnMore.setAttribute( + "value", + SecurityLevelStrings.security_level_learn_more + ); + this._elements.restoreDefaultsButton.textContent = + SecurityLevelStrings.security_level_restore; + this._elements.advancedSecuritySettings.textContent = + SecurityLevelStrings.security_level_change; + this._elements.panel.addEventListener("onpopupshown", e => { this.onPopupShown(e); }); @@ -251,15 +329,16 @@ const SecurityLevelPanel = { // Descriptions change based on security level if (level) { this._elements.icon.setAttribute("level", level); - document.l10n.setAttributes( - this._elements.labelLevel, - `security-level-${level}-label` + this._elements.labelLevel.setAttribute( + "value", + SecurityLevelStrings[`security_level_${level}`] ); - document.l10n.setAttributes(summary, `security-level-${level}-summary`); + summary.textContent = + SecurityLevelStrings[`security_level_${level}_summary`]; } // override the summary text with custom warning if (custom) { - document.l10n.setAttributes(summary, "security-level-custom-summary"); + summary.textContent = SecurityLevelStrings.security_level_custom_summary; } },
@@ -349,19 +428,58 @@ const SecurityLevelPreferences = { SecurityLevelPreferences.selectSecurityLevel );
- const populateRadioElements = vboxQuery => { - const vbox = groupbox.querySelector(vboxQuery); + groupbox.querySelector("h2").textContent = + SecurityLevelStrings.security_level; + groupbox.querySelector("#securityLevel-overview").textContent = + SecurityLevelStrings.security_level_overview; + groupbox + .querySelector("#securityLevel-learnMore") + .setAttribute("value", SecurityLevelStrings.security_level_learn_more); + + const populateRadioElements = (level, descr) => { + const vbox = groupbox.querySelector(`#securityLevel-vbox-${level}`); + vbox + .querySelector("radio") + .setAttribute("label", SecurityLevelStrings[`security_level_${level}`]); + vbox + .querySelector(".securityLevel-customWarning") + .setAttribute("value", SecurityLevelStrings.security_level_custom); + vbox.querySelector(".summary").textContent = + SecurityLevelStrings[`security_level_${level}_summary`]; const labelRestoreDefaults = vbox.querySelector( ".securityLevel-restoreDefaults" ); + labelRestoreDefaults.setAttribute( + "value", + SecurityLevelStrings.security_level_restore + ); labelRestoreDefaults.addEventListener( "click", - SecurityLevelPreferences.restoreDefaults + SecurityLevelStrings.restoreDefaults ); + if (descr) { + const descrList = vbox.querySelector(".securityLevel-descriptionList"); + // TODO: Add the elements in securityLevelPreferences.inc.xhtml again + // when we switch to Fluent + for (const text of descr) { + let elem = document.createXULElement("description"); + elem.textContent = text; + elem.className = "indent"; + descrList.append(elem); + } + } }; - populateRadioElements("#securityLevel-vbox-standard"); - populateRadioElements("#securityLevel-vbox-safer"); - populateRadioElements("#securityLevel-vbox-safest"); + populateRadioElements("standard"); + populateRadioElements("safer", [ + SecurityLevelStrings.security_level_js_https_only, + SecurityLevelStrings.security_level_limit_typography, + SecurityLevelStrings.security_level_limit_media, + ]); + populateRadioElements("safest", [ + SecurityLevelStrings.security_level_js_disabled, + SecurityLevelStrings.security_level_limit_typography_svg, + SecurityLevelStrings.security_level_limit_media, + ]); },
_configUIFromPrefs() { diff --git a/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml b/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml index 05a127dd98f24..0347ab5e70854 100644 --- a/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml +++ b/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml @@ -9,7 +9,7 @@ <panelview id="securityLevel-panelview" descriptionheightworkaround="true"> <vbox id="securityLevel-vbox"> <box class="panel-header"> - <html:h1 data-l10n-id="security-level-header" /> + <html:h1 id="securityLevel-header"/> </box> <toolbarseparator></toolbarseparator> <vbox> @@ -17,7 +17,7 @@ <label id="securityLevel-level"/> <vbox> <spacer flex="1"/> - <label id="securityLevel-custom" data-l10n-id="security-level-custom"/> + <label id="securityLevel-custom"/> <spacer flex="1"/> </vbox> <spacer flex="1"/> @@ -29,8 +29,7 @@ href="about:manual#security-settings" useoriginprincipal="true" onclick="SecurityLevelPanel.hide();" - is="text-link" - data-l10n-id="security-level-learn-more"/> + is="text-link"/> <spacer/> </hbox> </vbox> diff --git a/browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml b/browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml index 8439e581af133..07d9a1d3b32d2 100644 --- a/browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml +++ b/browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml @@ -1,9 +1,9 @@ <groupbox id="securityLevel-groupbox" data-category="panePrivacy" hidden="true"> - <label><html:h2 data-l10n-id="security-level-header"/></label> + <label>html:h2/</label> <vbox data-subcategory="securitylevel" flex="1"> <description flex="1"> - <html:span data-l10n-id="security-level-overview" class="tail-with-learn-more"/> - <label data-l10n-id="security-level-learn-more" + <html:span id="securityLevel-overview" class="tail-with-learn-more"/> + <label id="securityLevel-learnMore" class="learnMore text-link" is="text-link" href="about:manual#security-settings" @@ -12,61 +12,49 @@ <radiogroup id="securityLevel-radiogroup"> <vbox id="securityLevel-vbox-standard"> <hbox> - <radio value="standard" data-l10n-id="security-level-standard-radio"/> + <radio value="standard"/> <vbox> <spacer flex="1"/> - <label class="securityLevel-customWarning" data-l10n-id="security-level-custom"/> + <label class="securityLevel-customWarning"/> <spacer flex="1"/> </vbox> <spacer flex="1"/> </hbox> <description flex="1" class="indent"> - <html:span data-l10n-id="security-level-standard-summary" - class="tail-with-learn-more"/> - <label class="securityLevel-restoreDefaults learnMore text-link" - data-l10n-id="security-level-restore-link"/> + <html:span class="summary tail-with-learn-more"/> + <label class="securityLevel-restoreDefaults learnMore text-link"/> </description> </vbox> <vbox id="securityLevel-vbox-safer"> <hbox> - <radio value="safer" data-l10n-id="security-level-safer-radio"/> + <radio value="safer"/> <vbox> <spacer flex="1"/> - <label class="securityLevel-customWarning" data-l10n-id="security-level-custom"/> + <label class="securityLevel-customWarning"/> <spacer flex="1"/> </vbox> </hbox> <description flex="1" class="indent"> - <html:span data-l10n-id="security-level-safer-summary" - class="tail-with-learn-more"/> - <label class="securityLevel-restoreDefaults learnMore text-link" - data-l10n-id="security-level-restore-link"/> + <html:span class="summary tail-with-learn-more"/> + <label class="securityLevel-restoreDefaults learnMore text-link"/> </description> <vbox class="securityLevel-descriptionList indent"> - <description data-l10n-id="security-level-js-https-only" class="indent"/> - <description data-l10n-id="security-level-limit-typography" class="indent"/> - <description data-l10n-id="security-level-limit-media" class="indent"/> </vbox> </vbox> <vbox id="securityLevel-vbox-safest"> <hbox> - <radio value="safest" data-l10n-id="security-level-safest-radio"/> + <radio value="safest"/> <vbox> <spacer flex="1"/> - <label class="securityLevel-customWarning" data-l10n-id="security-level-custom"/> + <label class="securityLevel-customWarning"/> <spacer flex="1"/> </vbox> </hbox> <description flex="1" class="indent"> - <html:span data-l10n-id="security-level-safest-summary" - class="tail-with-learn-more"/> - <label class="securityLevel-restoreDefaults learnMore text-link" - data-l10n-id="security-level-restore-link"/> + <html:span class="summary tail-with-learn-more"/> + <label class="securityLevel-restoreDefaults learnMore text-link"/> </description> <vbox class="securityLevel-descriptionList indent"> - <description data-l10n-id="security-level-js-disabled" class="indent"/> - <description data-l10n-id="security-level-limit-typography-svg" class="indent"/> - <description data-l10n-id="security-level-limit-media" class="indent"/> </vbox> </vbox> </radiogroup> diff --git a/browser/components/securitylevel/jar.mn b/browser/components/securitylevel/jar.mn index 61aa4169f9ece..ac8df00b15747 100644 --- a/browser/components/securitylevel/jar.mn +++ b/browser/components/securitylevel/jar.mn @@ -4,3 +4,8 @@ browser.jar: content/browser/securitylevel/securityLevelButton.css (content/securityLevelButton.css) content/browser/securitylevel/securityLevelPreferences.css (content/securityLevelPreferences.css) content/browser/securitylevel/securityLevelIcon.svg (content/securityLevelIcon.svg) + +securitylevel.jar: +# See New Identity for further information on how this works +% locale securitylevel en-US %locale/en-US/ + locale/en-US/securityLevel.properties (locale/en-US/securityLevel.properties) diff --git a/browser/components/securitylevel/locale/en-US/securityLevel.properties b/browser/components/securitylevel/locale/en-US/securityLevel.properties new file mode 100644 index 0000000000000..01a51e67f7f5b --- /dev/null +++ b/browser/components/securitylevel/locale/en-US/securityLevel.properties @@ -0,0 +1,30 @@ +# Generic terms +security_level = Security Level +security_level_standard = Standard +security_level_safer = Safer +security_level_safest = Safest +security_level_tooltip_standard = Security Level: Standard +security_level_tooltip_safer = Security Level: Safer +security_level_tooltip_safest = Security Level: Safest +# Shown only for custom level +security_level_custom = Custom +security_level_restore = Restore Defaults +security_level_learn_more = Learn more + +# Panel +security_level_change = Change… +security_level_standard_summary = All Tor Browser and website features are enabled. +security_level_safer_summary = Disables website features that are often dangerous, causing some sites to lose functionality. +security_level_safest_summary = Only allows website features required for static sites and basic services. These changes affect images, media, and scripts. +security_level_custom_summary = Your custom browser preferences have resulted in unusual security settings. For security and privacy reasons, we recommend you choose one of the default security levels. + +## Security level section in about:preferences#privacy +security_level_overview = Disable certain web features that can be used to attack your security and anonymity. +security_level_list_safer = At the safer setting: +security_level_list_safest = At the safest setting: +# Strings for descriptions +security_level_js_https_only = JavaScript is disabled on non-HTTPS sites. +security_level_js_disabled = JavaScript is disabled by default on all sites. +security_level_limit_typography = Some fonts and math symbols are disabled. +security_level_limit_typography_svg = Some fonts, icons, math symbols, and images are disabled. +security_level_limit_media = Audio and video (HTML5 media), and WebGL are click-to-play. diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index f32d574813a74..7b1ea43f8ef0e 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -261,6 +261,11 @@ #endif @RESPATH@/browser/features/*
+; Base Browser +@RESPATH@/browser/chrome/securitylevel.manifest +@RESPATH@/browser/chrome/securitylevel/ +@RESPATH@/browser/components/SecurityLevel.manifest + ; [DevTools Startup Files] @RESPATH@/browser/chrome/devtools-startup@JAREXT@ @RESPATH@/browser/chrome/devtools-startup.manifest @@ -486,5 +491,3 @@ i686/gmp-clearkey/0.1/clearkey.dll ; build, which, practically speaking, is the case. @BINPATH@/gmp-clearkey/0.1/manifest.json #endif - -@RESPATH@/browser/components/SecurityLevel.manifest diff --git a/browser/locales/en-US/browser/base-browser/securityLevel.ftl b/browser/locales/en-US/browser/base-browser/securityLevel.ftl deleted file mode 100644 index ef1ca39a3d492..0000000000000 --- a/browser/locales/en-US/browser/base-browser/securityLevel.ftl +++ /dev/null @@ -1,66 +0,0 @@ --security-level = Security Level --security-level-standard = Standard --security-level-safer = Safer --security-level-safest = Safest --security-level-tooltip-standard = Security Level: Standard --security-level-tooltip-safer = Security Level: Safer --security-level-tooltip-safest = Security Level: Safest -# Shown only for custom level --security-level-restore = Restore Defaults - -## Security level button: when changing level, the id will be updated accordingly -# Not yet loaded (generic placeholders) -security-level-button = - .tooltiptext = { -security-level } - .label = { -security-level } -security-level-button-standard = - .tooltiptext = { -security-level-tooltip-standard } - .label = { -security-level-tooltip-standard } -security-level-button-safer = - .tooltiptext = { -security-level-tooltip-safer } - .label = { -security-level-tooltip-safer } -security-level-button-safest = - .tooltiptext = { -security-level-tooltip-safest } - .label = { -security-level-tooltip-safest } - -## Security level panel -security-level-change = Change… -security-level-standard-label = - .value = { -security-level-standard } -security-level-standard-radio = - .label = { -security-level-standard } -security-level-standard-summary = All Tor Browser and website features are enabled. -security-level-safer-label = - .value = { -security-level-safer } -security-level-safer-radio = - .label = { -security-level-safer } -security-level-safer-summary = Disables website features that are often dangerous, causing some sites to lose functionality. -security-level-safest-label = - .value = { -security-level-safest } -security-level-safest-radio = - .label = { -security-level-safest } -security-level-safest-summary = Only allows website features required for static sites and basic services. These changes affect images, media, and scripts. -security-level-custom = - .value = Custom -security-level-custom-summary = Your custom browser preferences have resulted in unusual security settings. For security and privacy reasons, we recommend you choose one of the default security levels. -security-level-restore-defaults = { -security-level-restore } - -## Security level section in about:preferences#privacy -security-level-overview = Disable certain web features that can be used to attack your security and anonymity. -security-level-list-safer = - .value = At the safer setting: -security-level-list-safest = - .value = At the safest setting: -security-level-restore-link = - .value = { -security-level-restore } -# Strings for descriptions -security-level-js-https-only = JavaScript is disabled on non-HTTPS sites. -security-level-js-disabled = JavaScript is disabled by default on all sites. -security-level-limit-typography = Some fonts and math symbols are disabled. -security-level-limit-typography-svg = Some fonts, icons, math symbols, and images are disabled. -security-level-limit-media = Audio and video (HTML5 media), and WebGL are click-to-play. - -## Shared strings (both panel and preferences) -security-level-header = { -security-level } -security-level-learn-more = - .value = Learn more
This is an automated email from the git hooks/post-receive script.
richard pushed a commit to branch tor-browser-91.11.0esr-12.0-1 in repository tor-browser.
commit c0426df7f7b372c11bbc16d0f78fcf7db5502acc Author: Pier Angelo Vendrame pierov@torproject.org AuthorDate: Mon Jul 25 10:40:35 2022 +0200
Bug 40926: Implemented the New Identity feature --- browser/base/content/appmenu-viewcache.inc.xhtml | 12 +- browser/base/content/browser-menubar.inc | 5 +- browser/base/content/browser-sets.inc | 2 +- browser/base/content/browser.js | 10 + browser/base/content/navigator-toolbox.inc.xhtml | 5 +- browser/components/moz.build | 1 + .../components/newidentity/content/newidentity.js | 566 +++++++++++++++++++++ browser/components/newidentity/jar.mn | 13 + .../locale/en-US/newIdentity.properties | 8 + browser/components/newidentity/moz.build | 1 + browser/installer/package-manifest.in | 2 + 11 files changed, 608 insertions(+), 17 deletions(-)
diff --git a/browser/base/content/appmenu-viewcache.inc.xhtml b/browser/base/content/appmenu-viewcache.inc.xhtml index a473509f1647c..b3309c3e91fb0 100644 --- a/browser/base/content/appmenu-viewcache.inc.xhtml +++ b/browser/base/content/appmenu-viewcache.inc.xhtml @@ -65,11 +65,9 @@ command="Browser:RestoreLastSession" hidden="true"/> <toolbarseparator/> - <toolbarbutton id="appMenuNewIdentity" + <toolbarbutton id="appMenu-new-identity" class="subviewbutton subviewbutton-iconic" - key="torbutton-new-identity-key" - label="&torbutton.context_menu.new_identity;" - oncommand="torbutton_new_identity();"/> + key="new-identity-key"/> <toolbarbutton id="appMenuNewCircuit" class="subviewbutton subviewbutton-iconic" key="torbutton-new-circuit-key" @@ -269,11 +267,9 @@ key="key_privatebrowsing" command="Tools:PrivateBrowsing"/> <toolbarseparator/> - <toolbarbutton id="appMenuNewIdentity" + <toolbarbutton id="appMenu-new-identity2" class="subviewbutton" - key="torbutton-new-identity-key" - label="&torbutton.context_menu.new_identity_sentence_case;" - oncommand="torbutton_new_identity();"/> + key="new-identity-key"/> <toolbarbutton id="appMenuNewCircuit" class="subviewbutton" key="torbutton-new-circuit-key" diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc index d3c272f8dc392..45d462671ccc2 100644 --- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -40,10 +40,7 @@ #endif <menuseparator/> <menuitem id="menu_newIdentity" - accesskey="&torbutton.context_menu.new_identity_key;" - key="torbutton-new-identity-key" - label="&torbutton.context_menu.new_identity;" - oncommand="torbutton_new_identity();"/> + key="new-identity-key"/> <menuitem id="menu_newCircuit" accesskey="&torbutton.context_menu.new_circuit_key;" key="torbutton-new-circuit-key" diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index c3129d6aae077..51407a2ad4367 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -383,6 +383,6 @@ data-l10n-id="hide-other-apps-shortcut" modifiers="accel,alt"/> #endif - <key id="torbutton-new-identity-key" modifiers="accel shift" key="U" oncommand="torbutton_new_identity()"/> + <key id="new-identity-key" modifiers="accel shift" key="U" oncommand="NewIdentityButton.onCommand(event)"/> <key id="torbutton-new-circuit-key" modifiers="accel shift" key="L" oncommand="torbutton_new_circuit()"/> </keyset> diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index faf6433ccacf8..4dff70094d667 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -230,6 +230,11 @@ XPCOMUtils.defineLazyScriptGetter( ["SecurityLevelButton"], "chrome://browser/content/securitylevel/securityLevel.js" ); +XPCOMUtils.defineLazyScriptGetter( + this, + ["NewIdentityButton"], + "chrome://browser/content/newidentity.js" +); XPCOMUtils.defineLazyScriptGetter( this, ["OnionAuthPrompt"], @@ -1778,6 +1783,9 @@ var gBrowserInit = { // Init the SecuritySettingsButton SecurityLevelButton.init();
+ // Init the NewIdentityButton + NewIdentityButton.init(); + // Init the OnionAuthPrompt OnionAuthPrompt.init();
@@ -2516,6 +2524,8 @@ var gBrowserInit = {
SecurityLevelButton.uninit();
+ NewIdentityButton.uninit(); + OnionAuthPrompt.uninit();
TorBootstrapUrlbar.uninit(); diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml index b881492864ae9..eaaa6c1538d1f 100644 --- a/browser/base/content/navigator-toolbox.inc.xhtml +++ b/browser/base/content/navigator-toolbox.inc.xhtml @@ -577,10 +577,7 @@ ondragenter="newWindowButtonObserver.onDragOver(event)" ondragexit="newWindowButtonObserver.onDragExit(event)"/>
- <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - label="&torbutton.context_menu.new_identity;" - oncommand="torbutton_new_identity();" - tooltiptext="&torbutton.context_menu.new_identity;"/> + <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional"/>
<toolbarbutton id="new-circuit-button" class="toolbarbutton-1 chromeclass-toolbar-additional" label="&torbutton.context_menu.new_circuit;" diff --git a/browser/components/moz.build b/browser/components/moz.build index 0eefdd0a06349..eedc66029ce69 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -37,6 +37,7 @@ DIRS += [ "enterprisepolicies", "extensions", "migration", + "newidentity", "newtab", "onionservices", "originattributes", diff --git a/browser/components/newidentity/content/newidentity.js b/browser/components/newidentity/content/newidentity.js new file mode 100644 index 0000000000000..a1d10a910cabe --- /dev/null +++ b/browser/components/newidentity/content/newidentity.js @@ -0,0 +1,566 @@ +"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: `${brandShortName} will close all windows and tabs. All website sessions will be lost. \nRestart ${brandShortName} now to reset your identity?`, + new_identity_ask_again: "Never ask me again", + new_identity_menu_accesskey: "I", + }; + let bundle = null; + try { + bundle = Services.strings.createBundle( + "chrome://newidentity/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 + ); + } + 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 = (() => { + let scope = {}; + ChromeUtils.import("resource://gre/modules/Console.jsm", scope); + const consoleOptions = { + maxLogLevel: "info", + prefix: "NewIdentity", + }; + return new scope.ConsoleAPI(consoleOptions); + })(); + + const topics = Object.freeze({ + newIdentityRequested: "new-identity-requested", + }); + + class NewIdentityImpl { + async run() { + logger.debug("Disabling JS"); + this.disableAllJS(); + await this.clearState(); + this.broadcast(); + this.openNewWindow(); + this.closeOldWindow(); + } + + // 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) { + for (const browser of win.gBrowser?.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(); + await this.clearStorage(); + this.clearPreferencesAndPermissions(); + 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("extensions.torbutton.close_newnym")) { + 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("extensions.torbutton.clear_http_auth")) { + 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/n... + 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(); + } + + async clearData(flags) { + return new Promise((resolve, reject) => { + Services.clearData.deleteData(flags, { + onDataDeleted(code) { + if (code === Cr.NS_OK) { + resolve(); + } else { + reject( + new Error(`Error deleting data with flags ${flags}: ${code}`) + ); + } + }, + }); + }); + } + + 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); + } + } + + async clearStorage() { + logger.info("Clearing Disk and Memory Caches"); + try { + Services.cache2.clear(); + } catch (e) { + logger.error("Exception on cache clearing", e); + } + + logger.info("Clearing storage, media devices and predictor network data"); + try { + await this.clearData( + Services.clearData.CLEAR_DOM_STORAGES | + Services.clearData.CLEAR_MEDIA_DEVICES | + Services.clearData.CLEAR_PREDICTOR_NETWORK_DATA + ); + } catch (e) { + logger.error("Exception on storage 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); + } + + 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"); + // 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? + OpenBrowserWindow(); + } + + 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#.... + // 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() { + CustomizableUI.addListener(this); + + const button = document.querySelector("#new-identity-button"); + if (button) { + button.setAttribute("tooltiptext", 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); + appButton.addEventListener("command", () => { + this.onCommand(); + }); + } + const appButton2 = viewCache.querySelector("#appMenu-new-identity2"); + if (appButton2) { + appButton2.setAttribute( + "label", + NewIdentityStrings.new_identity_sentence_case + ); + appButton2.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() { + CustomizableUI.removeListener(this); + }, + + onCustomizeStart(window) { + const button = document.querySelector("#new-identity-button"); + button.setAttribute("label", NewIdentityStrings.new_identity); + }, + + onWidgetAfterDOMChange(aNode, aNextNode, aContainer, aWasRemoval) {}, + + 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 = "extensions.torbutton.confirm_newnym"; + const shouldConfirm = Services.prefs.getBoolPref(prefConfirm); + if (shouldConfirm) { + // Display two buttons, both with string titles. + const flags = Services.prompt.STD_YES_NO_BUTTONS; + const askAgain = { value: false }; + const confirmed = + Services.prompt.confirmEx( + null, + "", + NewIdentityStrings.new_identity_prompt, + flags, + null, + null, + null, + NewIdentityStrings.new_identity_ask_again, + askAgain + ) == 0; + Services.prefs.setBoolPref(prefConfirm, !askAgain.value); + if (!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; + } + }, + }; +}); diff --git a/browser/components/newidentity/jar.mn b/browser/components/newidentity/jar.mn new file mode 100644 index 0000000000000..57b30b32c0e18 --- /dev/null +++ b/browser/components/newidentity/jar.mn @@ -0,0 +1,13 @@ +browser.jar: + content/browser/newidentity.js (content/newidentity.js) + +newidentity.jar: +# We need to list at least one locale here, to make Firefox load the localized +# copy of properties at chrome://newidentity/locale/newIdentity.properties. +# Ideally, we should use @AB_CD@.jar to automatically copy all the locales +# Firefox is built with. But we only provide English here, and injecting the +# translated files directly to the omni.ja works better for us, for the time +# being. In addition to inject the properties files, we also add the +# corresponding locale line to chrome/chrome.manifest. +% locale newidentity en-US %locale/en-US/ + locale/en-US/newIdentity.properties (locale/en-US/newIdentity.properties) diff --git a/browser/components/newidentity/locale/en-US/newIdentity.properties b/browser/components/newidentity/locale/en-US/newIdentity.properties new file mode 100644 index 0000000000000..54eeca135a5e1 --- /dev/null +++ b/browser/components/newidentity/locale/en-US/newIdentity.properties @@ -0,0 +1,8 @@ +new_identity = New Identity +# This is the string for the hamburger menu +new_identity_sentence_case = New identity +# %S is the application name. Keep it as a placeholder +new_identity_prompt = %S will close all windows and tabs. All website sessions will be lost. \nRestart %S now to reset your identity? +new_identity_ask_again = Never ask me again +# Shown in the File menu (use Alt to show File, if you do not see) +new_identity_menu_accesskey = I diff --git a/browser/components/newidentity/moz.build b/browser/components/newidentity/moz.build new file mode 100644 index 0000000000000..2661ad7cb9f3d --- /dev/null +++ b/browser/components/newidentity/moz.build @@ -0,0 +1 @@ +JAR_MANIFESTS += ["jar.mn"] diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 7b1ea43f8ef0e..29aa2639e5d9e 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -262,6 +262,8 @@ @RESPATH@/browser/features/*
; Base Browser +@RESPATH@/browser/chrome/newidentity.manifest +@RESPATH@/browser/chrome/newidentity/ @RESPATH@/browser/chrome/securitylevel.manifest @RESPATH@/browser/chrome/securitylevel/ @RESPATH@/browser/components/SecurityLevel.manifest
tor-commits@lists.torproject.org