commit e59f6df84dcfde500f41eefb608dd878a7fc9d6b Author: Arthur Edelstein arthuredelstein@gmail.com Date: Mon Oct 17 17:25:59 2016 -0700
Bug 20347: Remove "Custom" checkbox; show "Restore defaults" button
This patch moves the security slider code from torbutton.js to its own file (security-prefs.js) and refactors it. --- src/chrome/content/preferences.js | 149 ++++++------------ src/chrome/content/preferences.xul | 53 ++++--- src/chrome/content/torbutton.js | 309 ++++--------------------------------- src/chrome/locale/en/torbutton.dtd | 5 +- src/modules/security-prefs.js | 130 ++++++++++++++++ src/modules/utils.js | 21 ++- 6 files changed, 256 insertions(+), 411 deletions(-)
diff --git a/src/chrome/content/preferences.js b/src/chrome/content/preferences.js index 1d85cde..7856ef1 100644 --- a/src/chrome/content/preferences.js +++ b/src/chrome/content/preferences.js @@ -1,105 +1,44 @@ -// Bug 1506 P1: Most of this code needs to go away. See also Bug 3100. - -// PREFERences dialog functions -// torbutton_prefs_init() -- on dialog load -// torbutton_prefs_save() -- on dialog save - -const Cc = Components.classes, Ci = Components.interfaces; - - -function torbutton_prefs_init(doc) { - torbutton_log(2, "called prefs_init()"); - - var o_torprefs = torbutton_get_prefbranch('extensions.torbutton.'); - - let sec_slider = doc.getElementById('torbutton_sec_slider'); - let sec_custom = doc.getElementById('torbutton_sec_custom'); - let custom_values = o_torprefs.getBoolPref('security_custom'); - sec_slider.value = o_torprefs.getIntPref('security_slider'); - sec_custom.checked = custom_values; - sec_custom.disabled = !custom_values; - torbutton_set_slider_text(doc, sec_custom.checked); - // If the custom checkbox is checked and the user is done with dragging - // uncheck the checkbox to allow setting the (newly) chosen security level. - sec_slider.dragStateChanged = function(isDragging) { - if (!isDragging && sec_custom.checked) { - sec_custom.checked = false; - sec_custom.disabled = true; - } - } - sec_slider.valueChanged = function(which, newValue, userChanged) { - torbutton_set_slider_text(doc, false); - } -} - -function torbutton_prefs_save(doc) { - // Disable the Accept button once the user clicked on it as clicking on - // our active Accept button more than once can lead to all sort of weird - // behavior. See bug 11763 for an example. - doc.documentElement.getButton("accept").disabled = true; - torbutton_log(2, "called prefs_save()"); - var o_torprefs = torbutton_get_prefbranch('extensions.torbutton.'); - - o_torprefs.setBoolPref('security_custom', - doc.getElementById('torbutton_sec_custom').checked); - o_torprefs.setIntPref('security_slider', - doc.getElementById('torbutton_sec_slider').value); - - // If we have non-custom Security Slider settings update them now. - if (!o_torprefs.getBoolPref('security_custom')) { - let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] - .getService(Components.interfaces.nsIWindowMediator); - let win = wm.getMostRecentWindow("navigator:browser"); - win.torbutton_update_security_slider(); - } -} - -function torbutton_toggle_slider(doc, pos) { - doc.getElementById("torbutton_sec_slider").value = pos; - // Make sure the custom checkbox is unchecked as the user seems to want one - // of the defined security levels. - let sec_custom = doc.getElementById("torbutton_sec_custom"); - if (sec_custom.checked) { - sec_custom.checked = false; - } - torbutton_set_slider_text(doc, false); -} - -function torbutton_set_slider_text(doc, custom) { - let level = doc.getElementById("torbutton_sec_slider").value; - if (custom) { - level = 5; - } - switch (level) { - case (1): - doc.getElementById("desc_low").collapsed = true; - doc.getElementById("desc_medium_low").collapsed = true; - doc.getElementById("desc_medium_high").collapsed = true; - doc.getElementById("desc_high").collapsed = false; - break; - case (2): - doc.getElementById("desc_low").collapsed = true; - doc.getElementById("desc_medium_low").collapsed = true; - doc.getElementById("desc_medium_high").collapsed = false; - doc.getElementById("desc_high").collapsed = true; - break; - case (3): - doc.getElementById("desc_low").collapsed = true; - doc.getElementById("desc_medium_low").collapsed = false; - doc.getElementById("desc_medium_high").collapsed = true; - doc.getElementById("desc_high").collapsed = true; - break; - case (4): - doc.getElementById("desc_low").collapsed = false; - doc.getElementById("desc_medium_low").collapsed = true; - doc.getElementById("desc_medium_high").collapsed = true; - doc.getElementById("desc_high").collapsed = true; - break; - case (5): - doc.getElementById("desc_low").collapsed = true; - doc.getElementById("desc_medium_low").collapsed = true; - doc.getElementById("desc_medium_high").collapsed = true; - doc.getElementById("desc_high").collapsed = true; - break; - } -} +// # Security Settings User Interface + +// Utilities +let { utils: Cu } = Components; +let { getBoolPref, getIntPref, setBoolPref, setIntPref } = + Cu.import("resource://gre/modules/Services.jsm").Services.prefs; + +// Description elements have the follow names. +const descNames = + [, "desc_high", "desc_medium_high", "desc_medium_low", "desc_low"]; + +// A single `state` object that reflects the user settings in this UI. +let state = { slider : 0, custom : false}; + +// Set the desired slider value and update UI. +function torbutton_set_slider(sliderPosition) { + state.slider = sliderPosition; + let slider = document.getElementById("torbutton_sec_slider"); + slider.value = sliderPosition; + let descs = descNames.map(name => document.getElementById(name)); + descs.forEach((desc, i) => desc.collapsed = sliderPosition !== i); +}; + +// Set the desired custom value and update UI. +function torbutton_set_custom(customValue) { + state.custom = customValue; + let sliderSettings = document.getElementById("torbutton_slider_settings"); + let customSettings = document.getElementById("torbutton_custom_settings"); + sliderSettings.hidden = customValue; + customSettings.hidden = !customValue; +}; + +// Read prefs 'extensions.torbutton.security_slider' and +// 'extensions.torbutton.security_custom', and initialize the UI. +function torbutton_init_security_ui() { + torbutton_set_slider(getIntPref("extensions.torbutton.security_slider")); + torbutton_set_custom(getBoolPref("extensions.torbutton.security_custom")); +}; + +// Write the two prefs from the current settings. +function torbutton_save_security_settings() { + setIntPref("extensions.torbutton.security_slider", state.slider); + setBoolPref("extensions.torbutton.security_custom", state.custom); +}; diff --git a/src/chrome/content/preferences.xul b/src/chrome/content/preferences.xul index 574932e..53abd7f 100644 --- a/src/chrome/content/preferences.xul +++ b/src/chrome/content/preferences.xul @@ -10,64 +10,59 @@ title="&torbutton.prefs.security_settings;" buttons="accept,cancel" persist="screenX screenY width height" - onload="torbutton_prefs_init(document)" + onload="torbutton_init_security_ui()" align="stretch" pack="center" - maxheight="350" + maxheight="300" + minwidth="300" maxwidth="400" - ondialogaccept="torbutton_prefs_save(document)" > + ondialogaccept="torbutton_save_security_settings()" + width="400" >
<script type="application/x-javascript" src="torbutton_util.js"/> <script type="application/x-javascript" src="preferences.js"/> <vbox flex="1" align="stretch"> <groupbox align="stretch" flex="1"> <!-- security settings container --> <caption label="&torbutton.prefs.sec_caption;"/> - <hbox flex="1" align="stretch"> + <hbox id="torbutton_slider_settings" flex="1" align="stretch" hidden="false"> <vbox> <hbox height="200"> <vbox> <scale id="torbutton_sec_slider" flex="1" min="1" max="4" - movetoclick="true" orient="vertical"/> + movetoclick="true" orient="vertical" + onchange="torbutton_set_slider(this.value)"/> </vbox> <vbox> <hbox flex="1" align="start"> <description id="torbutton_sec_high" - tooltip="high_preview" - onclick="torbutton_toggle_slider(document, 1);"> + onclick="torbutton_set_slider(1);" + tooltip="high_preview"> &torbutton.prefs.sec_high; </description> </hbox> <hbox flex="1" align="center"> <description id="torbutton_sec_med_high" - tooltip="mh_preview" - onclick="torbutton_toggle_slider(document, 2);"> + onclick="torbutton_set_slider(2);" + tooltip="mh_preview"> &torbutton.prefs.sec_med_high; </description> </hbox> <hbox flex="1" align="center"> <description id="torbutton_sec_med_low" - tooltip="ml_preview" - onclick="torbutton_toggle_slider(document, 3);"> + onclick="torbutton_set_slider(3);" + tooltip="ml_preview"> &torbutton.prefs.sec_med_low; </description> </hbox> <hbox flex="1" align="end"> <description id="torbutton_sec_low" - tooltip="low_preview" - onclick="torbutton_toggle_slider(document, 4);"> + onclick="torbutton_set_slider(4);" + tooltip="low_preview"> &torbutton.prefs.sec_low; </description> </hbox> </vbox> </hbox> - <hbox> - <!-- We are using |oncommand| instead of |onclick| as the former does - not fire if the checkbox is disabled and it does fire after the - checkbox adapted its state. --> - <checkbox id="torbutton_sec_custom" flex="1" - oncommand="torbutton_set_slider_text(document, event.target.checked);" - label="&torbutton.prefs.sec_custom;"/> - </hbox> </vbox> <!-- A width of 400 is already too much for OS X it seems. The above spacer tag would basically be useless and the layout ugly. --> @@ -161,6 +156,20 @@ </vbox> </vbox> </hbox> + <vbox id="torbutton_custom_settings" + hidden="true" + width="300" + height="200" + style="overflow:auto;"> + <description> + &torbutton.prefs.custom_warning; + </description> + <hbox> + <button id="torbutton_restore_defaults_button" + oncommand="torbutton_set_custom(false);" + label="&torbutton.prefs.restore_defaults;"/> + </hbox> + </vbox> </groupbox> </vbox>
@@ -200,4 +209,4 @@ html:br</html:br> html:div&torbutton.prefs.sec_low_usable_desc;</html:div> </tooltip> -</dialog> + </dialog> diff --git a/src/chrome/content/torbutton.js b/src/chrome/content/torbutton.js index 9a8b9e2..60f12d6 100644 --- a/src/chrome/content/torbutton.js +++ b/src/chrome/content/torbutton.js @@ -11,6 +11,7 @@ let { LoadContextInfo } = Cu.import('resource://gre/modules/LoadContextInfo.jsm' let { Services } = Cu.import("resource://gre/modules/Services.jsm"); let { showDialog } = Cu.import("resource://torbutton/modules/utils.js"); let { unescapeTorString } = Cu.import("resource://torbutton/modules/utils.js"); +let SecurityPrefs = Cu.import("resource://torbutton/modules/security-prefs.js");
const k_tb_last_browser_version_pref = "extensions.torbutton.lastBrowserVersion"; const k_tb_browser_update_needed_pref = "extensions.torbutton.updateNeeded"; @@ -45,8 +46,6 @@ var m_tb_orig_BrowserOnAboutPageLoad = null; var m_tb_domWindowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor). getInterface(Ci.nsIDOMWindowUtils);
-var m_tb_sliderUpdate = false; - // Bug 1506 P1: This object is only for updating the UI for toggling and style var torbutton_window_pref_observer = { @@ -86,11 +85,7 @@ var torbutton_unique_pref_observer = m_tb_prefs.addObserver("network.cookie", this, false); m_tb_prefs.addObserver("browser.privatebrowsing.autostart", this, false); m_tb_prefs.addObserver("javascript", this, false); - m_tb_prefs.addObserver("gfx", this, false); m_tb_prefs.addObserver("noscript", this, false); - m_tb_prefs.addObserver("media", this, false); - m_tb_prefs.addObserver("mathml", this, false); - m_tb_prefs.addObserver("svg", this, false); m_tb_prefs.addObserver("plugin.disable", this, false); m_tb_prefs.addObserver("privacy.thirdparty.isolate", this, false); m_tb_prefs.addObserver("privacy.resistFingerprinting", this, false); @@ -107,11 +102,10 @@ var torbutton_unique_pref_observer = m_tb_prefs.removeObserver("network.cookie", this); m_tb_prefs.removeObserver("browser.privatebrowsing.autostart", this); m_tb_prefs.removeObserver("javascript", this); - m_tb_prefs.removeObserver("gfx", this); m_tb_prefs.removeObserver("noscript", this); - m_tb_prefs.removeObserver("media", this); - m_tb_prefs.removeObserver("mathml", this); - m_tb_prefs.removeObserver("svg", this); + m_tb_prefs.removeObserver("plugin.disable", this); + m_tb_prefs.removeObserver("privacy.thirdparty.isolate", this); + m_tb_prefs.removeObserver("privacy.resistFingerprinting", this);
var observerService = Cc["@mozilla.org/observer-service;1"]. getService(Ci.nsIObserverService); @@ -149,7 +143,9 @@ var torbutton_unique_pref_observer = }
if (topic != "nsPref:changed") return; - + if (data.startsWith("noscript.")) { + torbutton_update_noscript_button(); + } switch (data) { case "network.cookie.cookieBehavior": var val = m_tb_prefs.getIntPref("network.cookie.cookieBehavior"); @@ -180,42 +176,6 @@ var torbutton_unique_pref_observer = case "extensions.torbutton.hide_sync_ui": torbutton_update_sync_ui(); break; - case "gfx.font_rendering.opentype_svg.enabled": - case "javascript.options.ion.content": - case "javascript.options.typeinference": - case "noscript.forbidMedia": - case "media.webaudio.enabled": - case "mathml.disabled": - case "javascript.options.baselinejit.content": - case "noscript.forbidFonts": - case "noscript.globalHttpsWhitelist": - case "noscript.global": - case "svg.in-content.enabled": - // |m_tb_slider_update| is only set if the user updated a - // preference under control of the security slider via the - // slider on the Torbutton dialog. This in turn means we can - // skip the code dealing with setting/unsetting the custom mode - // in this case. - if (!m_tb_sliderUpdate) { - // Do we already have custom settings? - let customSlider = m_tb_prefs. - getBoolPref("extensions.torbutton.security_custom"); - // A preference governed by the security slider got changed - // but we are not in custom mode yet. Change that. - if (!customSlider) { - m_tb_prefs. - setBoolPref("extensions.torbutton.security_custom", - true); - } else { - // We are in custom mode. Check whether all prefs are - // reset and reset the mode if so. Otherwise we remain - // in custom mode. - torbutton_log(4, "custom mode and we got: " + data); - torbutton_security_slider_custom_check(m_tb_prefs. - getIntPref("extensions.torbutton.security_slider")); - } - } - break; } } } @@ -269,7 +229,9 @@ function torbutton_init_toolbutton() // called once per browser window.. This might belong in a component. function torbutton_init() { torbutton_log(3, 'called init()'); - + + SecurityPrefs.initialize(); + if (m_tb_wasinited) { return; } @@ -372,12 +334,6 @@ function torbutton_init() { torbutton_on_abouttor_load(aEvent.target); }, false, true);
- // Set some important security prefs according to the chosen security level - // if there are no custom settings to respect. - if (!m_tb_prefs.getBoolPref("extensions.torbutton.security_custom")) { - torbutton_update_security_slider(); - } - // XXX: Get rid of the cached asmjs (or IndexedDB) files on disk in case we // don't allow things saved to disk. This is an ad-hoc fix to work around // #19417. Once this is properly solved we should remove this code again. @@ -1805,228 +1761,6 @@ function torbutton_update_thirdparty_prefs() { m_tb_prefs.savePrefFile(null); }
-var torbutton_sec_ml_bool_prefs = { - "javascript.options.ion.content" : false, - "javascript.options.typeinference" : false, - "noscript.forbidMedia" : true, - "media.webaudio.enabled" : false, - "mathml.disabled" : true -}; - -var torbutton_sec_mh_bool_prefs = { - "javascript.options.baselinejit.content" : false, - "gfx.font_rendering.opentype_svg.enabled" : false, - "noscript.global" : false, - "noscript.globalHttpsWhitelist" : true -}; - -var torbutton_sec_h_bool_prefs = { - "noscript.forbidFonts" : true, - "noscript.global" : false, - "svg.in-content.enabled" : false -}; - -function torbutton_update_security_slider() { - // Avoid checking the custom settings checkbox. - m_tb_sliderUpdate = true; - let mode = m_tb_prefs.getIntPref("extensions.torbutton.security_slider"); - let capValue = m_tb_prefs.getCharPref("capability.policy.maonoscript.sites"); - switch (mode) { - case 1: - for (p in torbutton_sec_ml_bool_prefs) { - m_tb_prefs.setBoolPref(p, torbutton_sec_ml_bool_prefs[p]) - } - for (p in torbutton_sec_mh_bool_prefs) { - m_tb_prefs.setBoolPref(p, torbutton_sec_mh_bool_prefs[p]) - // noscript.globalHttpsWhitelist is special: We don't want it in this - // mode. - if (p === "noscript.globalHttpsWhitelist") { - m_tb_prefs.setBoolPref(p, !torbutton_sec_mh_bool_prefs[p]) - } - } - for (p in torbutton_sec_h_bool_prefs) { - m_tb_prefs.setBoolPref(p, torbutton_sec_h_bool_prefs[p]) - } - // Removing "https:" is needed due to a bug in older Noscript versions. - // We leave that in for a while as there may be users that were affected - // by this bug. Removing it immediately and having the auto-updater might - // leave users exposed to the problem. - if (capValue.indexOf(" https:") >= 0) { - m_tb_prefs.setCharPref("capability.policy.maonoscript.sites", - capValue.replace(" https:", "")); - } - break; - case 2: - for (p in torbutton_sec_ml_bool_prefs) { - m_tb_prefs.setBoolPref(p, torbutton_sec_ml_bool_prefs[p]) - } - // Order matters here as both the high mode and the medium-high mode - // share some preferences/values. So, let's revert the high mode - // preferences first and set the medium-high mode ones afterwards. - for (p in torbutton_sec_h_bool_prefs) { - m_tb_prefs.setBoolPref(p, !torbutton_sec_h_bool_prefs[p]) - } - for (p in torbutton_sec_mh_bool_prefs) { - m_tb_prefs.setBoolPref(p, torbutton_sec_mh_bool_prefs[p]) - } - break; - case 3: - for (p in torbutton_sec_ml_bool_prefs) { - m_tb_prefs.setBoolPref(p, torbutton_sec_ml_bool_prefs[p]) - } - for (p in torbutton_sec_mh_bool_prefs) { - m_tb_prefs.setBoolPref(p, !torbutton_sec_mh_bool_prefs[p]) - } - for (p in torbutton_sec_h_bool_prefs) { - m_tb_prefs.setBoolPref(p, !torbutton_sec_h_bool_prefs[p]) - } - // Removing "https:" is needed due to a bug in older Noscript versions. - // We leave that in for a while as there may be users that were affected - // by this bug. Removing it immediately and having the auto-updater might - // leave users exposed to the problem. - if (capValue.indexOf(" https:") >= 0) { - m_tb_prefs.setCharPref("capability.policy.maonoscript.sites", - capValue.replace(" https:", "")); - } - break; - case 4: - for (p in torbutton_sec_ml_bool_prefs) { - m_tb_prefs.setBoolPref(p, !torbutton_sec_ml_bool_prefs[p]) - } - for (p in torbutton_sec_mh_bool_prefs) { - m_tb_prefs.setBoolPref(p, !torbutton_sec_mh_bool_prefs[p]) - } - for (p in torbutton_sec_h_bool_prefs) { - m_tb_prefs.setBoolPref(p, !torbutton_sec_h_bool_prefs[p]) - } - // Removing "https:" is needed due to a bug in older Noscript versions. - // We leave that in for a while as there may be users that were affected - // by this bug. Removing it immediately and having the auto-updater might - // leave users exposed to the problem. - if (capValue.indexOf(" https:") >= 0) { - m_tb_prefs.setCharPref("capability.policy.maonoscript.sites", - capValue.replace(" https:", "")); - } - break; - } - /* Update the NoScript button to reflect any changes */ - try { - let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] - .getService(Components.interfaces.nsIWindowMediator); - let browserEnumerator = wm.getEnumerator("navigator:browser"); - - // Update every window's NoScript status... - while (browserEnumerator.hasMoreElements()) { - let win = browserEnumerator.getNext(); - win.noscriptOverlay._syncUINow(); - } - torbutton_log(3, 'Updated NoScript status for security slider'); - } catch(e) { - torbutton_log(4, 'Failed to update NoScript status for security slider: '+e); - } - torbutton_log(3, 'Security Slider Pref Update Complete'); - m_tb_sliderUpdate = false; -} - -// The user (re)set a pref which is relevant to the security slider while she -// was in custom mode. Check whether the preference values fit to the mode which -// is still on the slider. Iff so, we are leaving the custom mode. -function torbutton_security_slider_custom_check(mode) { - let capValue = m_tb_prefs.getCharPref("capability.policy.maonoscript.sites"); - switch (mode) { - case 1: - for (p in torbutton_sec_ml_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) !== torbutton_sec_ml_bool_prefs[p]) { - return; - } - } - for (p in torbutton_sec_mh_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) !== torbutton_sec_mh_bool_prefs[p]) { - // We don't want to have the whitelist in high mode. JavaScript is - // disabled globally. - if (p === "noscript.globalHttpsWhitelist") { - continue; - } - return; - } - } - for (p in torbutton_sec_h_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) !== torbutton_sec_h_bool_prefs[p]) { - return; - } - } - // We are still here which means all preferences are properly reset. Leave - // custom mode. - m_tb_prefs.setBoolPref("extensions.torbutton.security_custom", false); - break; - case 2: - for (p in torbutton_sec_ml_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) !== torbutton_sec_ml_bool_prefs[p]) { - return; - } - } - for (p in torbutton_sec_mh_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) !== torbutton_sec_mh_bool_prefs[p]) { - return; - } - } - for (p in torbutton_sec_h_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) === torbutton_sec_h_bool_prefs[p]) { - // We have the whitelist and JavaScript is disabled in medium-high - // mode as well. - if (p === "noscript.global") { - continue; - } - return; - } - } - // We are still here which means all preferences are properly reset. Leave - // custom mode. - m_tb_prefs.setBoolPref("extensions.torbutton.security_custom", false); - break; - case 3: - for (p in torbutton_sec_ml_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) !== torbutton_sec_ml_bool_prefs[p]) { - return; - } - } - for (p in torbutton_sec_mh_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) === torbutton_sec_mh_bool_prefs[p]) { - return; - } - } - for (p in torbutton_sec_h_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) === torbutton_sec_h_bool_prefs[p]) { - return; - } - } - // We are still here which means all preferences are properly reset. Leave - // custom mode. - m_tb_prefs.setBoolPref("extensions.torbutton.security_custom", false); - break; - case 4: - for (p in torbutton_sec_ml_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) === torbutton_sec_ml_bool_prefs[p]) { - return; - } - } - for (p in torbutton_sec_mh_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) === torbutton_sec_mh_bool_prefs[p]) { - return; - } - } - for (p in torbutton_sec_h_bool_prefs) { - if (m_tb_prefs.getBoolPref(p) === torbutton_sec_h_bool_prefs[p]) { - return; - } - } - // We are still here which means all preferences are properly reset. Leave - // custom mode. - m_tb_prefs.setBoolPref("extensions.torbutton.security_custom", false); - break; - } -} - function torbutton_close_tabs_on_new_identity() { var close_newnym = m_tb_prefs.getBoolPref("extensions.torbutton.close_newnym"); if (!close_newnym) { @@ -2829,4 +2563,27 @@ function torbutton_update_sync_ui() } }
+// Update the NoScript button to reflect any changes to noscript prefs +function torbutton_update_noscript_button() +{ + // Make sure pref values have fully propagated inside NoScript before + // we sync the UI. + setTimeout(() => { + try { + let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] + .getService(Components.interfaces.nsIWindowMediator); + let browserEnumerator = wm.getEnumerator("navigator:browser"); + // Update every window's NoScript status... + while (browserEnumerator.hasMoreElements()) { + let win = browserEnumerator.getNext(); + win.noscriptOverlay._syncUINow(); + } + torbutton_log(3, 'Updated NoScript status for security settings'); + } catch (e) { + torbutton_log(4, 'Failed to update NoScript status for security setings: '+e); + } + }, 0); +} + + //vim:set ts=4 diff --git a/src/chrome/locale/en/torbutton.dtd b/src/chrome/locale/en/torbutton.dtd index 56f663e..0c10406 100644 --- a/src/chrome/locale/en/torbutton.dtd +++ b/src/chrome/locale/en/torbutton.dtd @@ -11,7 +11,9 @@ <!ENTITY torbutton.context_menu.cookieProtections "Cookie Protections…"> <!ENTITY torbutton.context_menu.cookieProtections.key "C"> <!ENTITY torbutton.button.tooltip "Click to initialize Torbutton"> -<!ENTITY torbutton.prefs.security_settings "Security Settings"> +<!ENTITY torbutton.prefs.security_settings "Tor Browser Security Settings"> +<!ENTITY torbutton.prefs.restore_defaults "Restore Defaults"> +<!ENTITY torbutton.prefs.custom_warning "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."> <!ENTITY torbutton.cookiedialog.title "Manage Cookie Protections"> <!ENTITY torbutton.cookiedialog.lockCol "Protected"> <!ENTITY torbutton.cookiedialog.domainCol "Host"> @@ -57,5 +59,4 @@ <!ENTITY torbutton.prefs.sec_all_js_desc "JavaScript is disabled by default on all sites."> <!ENTITY torbutton.prefs.sec_webfonts_desc "Some fonts and icons may display incorrectly."> <!ENTITY torbutton.prefs.sec_webfonts_desc_tooltip "Website-provided font files are blocked."> -<!ENTITY torbutton.prefs.sec_custom "Custom Values"> <!ENTITY torbutton.circuit_display.title "Tor circuit for this site"> diff --git a/src/modules/security-prefs.js b/src/modules/security-prefs.js new file mode 100644 index 0000000..3710862 --- /dev/null +++ b/src/modules/security-prefs.js @@ -0,0 +1,130 @@ +// # Security Settings prefs (as controlled by the Security Slider) + +// ### Utilities + +let {classes: Cc, utils: Cu } = Components; +let { getBoolPref, setBoolPref, getIntPref, setIntPref } = + Cu.import("resource://gre/modules/Services.jsm").Services.prefs; +let { bindPref } = + Cu.import("resource://torbutton/modules/utils.js"); +let logger = Components.classes["@torproject.org/torbutton-logger;1"] + .getService(Components.interfaces.nsISupports).wrappedJSObject; +let log = (level, msg) => logger.log(level, msg); + +// ### Constants + +// __kSecuritySettings__. +// A table of all prefs bound to the security slider, and the value +// for each security setting. +const kSecuritySettings = { + // Preference name : [0, 1-high 2-mh 3-ml 4-low] + "javascript.options.ion.content" : [, false, false, false, true ], + "javascript.options.typeinference" : [, false, false, false, true ], + "noscript.forbidMedia" : [, true, true, true, false], + "media.webaudio.enabled" : [, false, false, false, true ], + "mathml.disabled" : [, true, true, true, false], + "javascript.options.baselinejit.content" : [, false, false, true, true ], + "gfx.font_rendering.opentype_svg.enabled" : [, false, false, true, true ], + "noscript.global" : [, false, false, true, true ], + "noscript.globalHttpsWhitelist" : [, false, true, false, false], + "noscript.forbidFonts" : [, true, false, false, false], + "svg.in-content.enabled" : [, false, true, true, true ], +}; + +// The Security Settings prefs in question. +const kSliderPref = "extensions.torbutton.security_slider"; +const kCustomPref = "extensions.torbutton.security_custom"; + +// ### Prefs + +// __write_setting_to_prefs(settingIndex)__. +// Take a given setting index and write the appropriate pref values +// to the pref database. +var write_setting_to_prefs = function (settingIndex) { + Object.keys(kSecuritySettings).forEach( + prefName => setBoolPref( + prefName, kSecuritySettings[prefName][settingIndex])); +}; + +// __read_setting_from_prefs()__. +// Read the current pref values, and decide if any of our +// security settings matches. Otherwise return null. +var read_setting_from_prefs = function () { + let prefNames = Object.keys(kSecuritySettings); + for (let settingIndex of [1, 2, 3, 4]) { + let possibleSetting = true; + // For the given settingIndex, check if all current pref values + // match the setting. + for (let prefName of prefNames) { + if (kSecuritySettings[prefName][settingIndex] !== + getBoolPref(prefName)) { + possibleSetting = false; + } + } + if (possibleSetting) { + // We have a match! + return settingIndex; + } + } + // No matching setting; return null. + return null; +}; + +// __watch_security_prefs(onSettingChanged)__. +// Whenever a pref bound to the security slider changes, onSettingChanged +// is called with the new security setting value (1,2,3,4 or null). +// Returns a zero-arg function that ends this binding. +var watch_security_prefs = function (onSettingChanged) { + let prefNames = Object.keys(kSecuritySettings); + let unbindFuncs = []; + for (let prefName of prefNames) { + unbindFuncs.push(bindPref( + prefName, () => onSettingChanged(read_setting_from_prefs()))); + } + // Call all the unbind functions. + return () => unbindFuncs.forEach(unbind => unbind()); +}; + +// __initialized__. +// Have we called initialize() yet? +var initialized = false; + +// __initialize()__. +// Defines the behavior of "extensions.torbutton.security_custom", +// "extensions.torbutton.security_slider", and the security-sensitive +// prefs declared in kSecuritySettings. +var initialize = function () { + // Only run once. + if (initialized) { + return; + } + log(4, "Initializing security-prefs.js"); + initialized = true; + // When security_custom is set to false, apply security_slider setting + // to the security-sensitive prefs. + bindPref(kCustomPref, function (custom) { + if (custom === false) { + write_setting_to_prefs(getIntPref(kSliderPref)); + } + }); + // If security_slider is given a new value, then security_custom should + // be set to false. + bindPref(kSliderPref, function (prefIndex) { + setBoolPref(kCustomPref, false); + write_setting_to_prefs(prefIndex); + }); + // If a security-sensitive pref changes, then decide if the set of pref values + // constitutes a security_slider setting or a custom value. + watch_security_prefs(settingIndex => { + if (settingIndex === null) { + setBoolPref(kCustomPref, true); + } else { + setIntPref(kSliderPref, settingIndex); + setBoolPref(kCustomPref, false); + } + }); + log(4, "security-prefs.js initialization complete"); +}; + +// Export initialize() function for external use. +let EXPORTED_SYMBOLS = ["initialize"]; diff --git a/src/modules/utils.js b/src/modules/utils.js index b303485..507f008 100644 --- a/src/modules/utils.js +++ b/src/modules/utils.js @@ -23,11 +23,11 @@ var getPrefValue = function (prefName) { } };
-// __bindPrefAndInit(prefName, prefHandler)__ -// Applies prefHandler to the current value of pref specified by prefName. -// Re-applies prefHandler whenever the value of the pref changes. +// __bindPref(prefName, prefHandler, init)__ +// Applies prefHandler whenever the value of the pref changes. +// If init is true, applies prefHandler to the current value. // Returns a zero-arg function that unbinds the pref. -var bindPrefAndInit = function (prefName, prefHandler) { +var bindPref = function (prefName, prefHandler, init = false) { let update = () => { prefHandler(getPrefValue(prefName)); }, observer = { observe : function (subject, topic, data) { if (data === prefName) { @@ -35,10 +35,19 @@ var bindPrefAndInit = function (prefName, prefHandler) { } } }; prefs.addObserver(prefName, observer, false); - update(); + if (init) { + update(); + } return () => { prefs.removeObserver(prefName, observer); }; };
+// __bindPrefAndInit(prefName, prefHandler)__ +// Applies prefHandler to the current value of pref specified by prefName. +// Re-applies prefHandler whenever the value of the pref changes. +// Returns a zero-arg function that unbinds the pref. +var bindPrefAndInit = (prefName, prefHandler) => + bindPref(prefName, prefHandler, true); + // ## Environment variables
// __env__. @@ -173,5 +182,5 @@ var unescapeTorString = function(str) { };
// Export utility functions for external use. -let EXPORTED_SYMBOLS = ["bindPrefAndInit", "getPrefValue", "getEnv", +let EXPORTED_SYMBOLS = ["bindPref", "bindPrefAndInit", "getEnv", "getPrefValue", "showDialog", "unescapeTorString"];