securityLevel.js (10486B)
1 "use strict"; 2 3 /* global AppConstants, Services, openPreferences, XPCOMUtils, gSubDialog */ 4 5 ChromeUtils.defineESModuleGetters(this, { 6 SecurityLevelPrefs: "resource://gre/modules/SecurityLevel.sys.mjs", 7 SecurityLevelUIUtils: "resource:///modules/SecurityLevelUIUtils.sys.mjs", 8 }); 9 10 /* 11 Security Level Button Code 12 13 Controls init and update of the security level toolbar button 14 */ 15 16 var SecurityLevelButton = { 17 _securityPrefsBranch: null, 18 /** 19 * Whether we have added popup listeners to the panel. 20 * 21 * @type {boolean} 22 */ 23 _panelPopupListenersSetup: false, 24 /** 25 * The toolbar button element. 26 * 27 * @type {Element} 28 */ 29 _button: null, 30 /** 31 * The button that the panel should point to. Either the toolbar button or the 32 * overflow button. 33 * 34 * @type {Element} 35 */ 36 _anchorButton: null, 37 38 _configUIFromPrefs() { 39 const level = SecurityLevelPrefs.securityLevelSummary; 40 this._button.setAttribute("level", level); 41 42 let l10nIdLevel; 43 switch (level) { 44 case "standard": 45 l10nIdLevel = "security-level-toolbar-button-standard"; 46 break; 47 case "safer": 48 l10nIdLevel = "security-level-toolbar-button-safer"; 49 break; 50 case "safest": 51 l10nIdLevel = "security-level-toolbar-button-safest"; 52 break; 53 case "custom": 54 l10nIdLevel = "security-level-toolbar-button-custom"; 55 break; 56 default: 57 throw Error(`Unhandled level: ${level}`); 58 } 59 document.l10n.setAttributes(this._button, l10nIdLevel); 60 }, 61 62 /** 63 * Open the panel popup for the button. 64 */ 65 openPopup() { 66 const overflowPanel = document.getElementById("widget-overflow"); 67 if (overflowPanel.contains(this._button)) { 68 // We are in the overflow panel. 69 // We first close the overflow panel, otherwise focus will not return to 70 // the nav-bar-overflow-button if the security level panel is closed with 71 // "Escape" (the navigation toolbar does not track focus when a panel is 72 // opened whilst another is already open). 73 // NOTE: In principle, using PanelMultiView would allow us to open panels 74 // from within another panel. However, when using panelmultiview for the 75 // security level panel, tab navigation was broken within the security 76 // level panel. PanelMultiView may be set up to work with a menu-like 77 // panel rather than our dialog-like panel. 78 overflowPanel.hidePopup(); 79 this._anchorButton = document.getElementById("nav-bar-overflow-button"); 80 } else { 81 this._anchorButton = this._button; 82 } 83 84 const panel = SecurityLevelPanel.panel; 85 if (!this._panelPopupListenersSetup) { 86 this._panelPopupListenersSetup = true; 87 // NOTE: We expect the _anchorButton to not change whilst the popup is 88 // open. 89 panel.addEventListener("popupshown", () => { 90 this._anchorButton.setAttribute("open", "true"); 91 }); 92 panel.addEventListener("popuphidden", () => { 93 this._anchorButton.removeAttribute("open"); 94 }); 95 } 96 97 panel.openPopup( 98 this._anchorButton.icon, 99 "bottomright topright", 100 0, 101 0, 102 false 103 ); 104 }, 105 106 init() { 107 // We first search in the DOM for the security level button. If it does not 108 // exist it may be in the toolbox palette. We still want to return the 109 // button in the latter case to allow it to be initialized or adjusted in 110 // case it is added back through customization. 111 this._button = 112 document.getElementById("security-level-button") || 113 window.gNavToolbox.palette.querySelector("#security-level-button"); 114 // Set a label to be be used as the accessible name, and to be shown in the 115 // overflow menu and during customization. 116 this._button.addEventListener("command", () => this.openPopup()); 117 // set the initial class based off of the current pref 118 this._configUIFromPrefs(); 119 120 this._securityPrefsBranch = Services.prefs.getBranch( 121 "browser.security_level." 122 ); 123 this._securityPrefsBranch.addObserver("", this); 124 125 SecurityLevelPanel.init(); 126 }, 127 128 uninit() { 129 this._securityPrefsBranch.removeObserver("", this); 130 this._securityPrefsBranch = null; 131 132 SecurityLevelPanel.uninit(); 133 }, 134 135 observe(subject, topic, data) { 136 switch (topic) { 137 case "nsPref:changed": 138 if (data === "security_slider" || data === "security_custom") { 139 this._configUIFromPrefs(); 140 } 141 break; 142 } 143 }, 144 }; /* SecurityLevelButton */ 145 146 /* 147 Security Level Panel Code 148 149 Controls init and update of the panel in the security level hanger 150 */ 151 152 var SecurityLevelPanel = { 153 _securityPrefsBranch: null, 154 _populated: false, 155 156 _populateXUL() { 157 this._elements = { 158 panel: document.getElementById("securityLevel-panel"), 159 levelName: document.getElementById("securityLevel-level"), 160 summary: document.getElementById("securityLevel-summary"), 161 }; 162 163 const learnMoreEl = document.getElementById("securityLevel-learnMore"); 164 learnMoreEl.addEventListener("click", () => { 165 this.hide(); 166 }); 167 168 document 169 .getElementById("securityLevel-settings") 170 .addEventListener("command", () => { 171 this.openSecuritySettings(); 172 }); 173 174 this._elements.panel.addEventListener("popupshown", () => { 175 // Bring focus into the panel by focusing the default button. 176 this._elements.panel.querySelector('button[default="true"]').focus(); 177 }); 178 179 this._populated = true; 180 this._configUIFromPrefs(); 181 }, 182 183 _configUIFromPrefs() { 184 if (!this._populated) { 185 return; 186 } 187 188 // get security prefs 189 const level = SecurityLevelPrefs.securityLevelSummary; 190 191 // Descriptions change based on security level 192 this._elements.panel.setAttribute("level", level); 193 let l10nIdLevel; 194 let l10nIdSummary; 195 switch (level) { 196 case "standard": 197 l10nIdLevel = "security-level-panel-level-standard"; 198 l10nIdSummary = "security-level-summary-standard"; 199 break; 200 case "safer": 201 l10nIdLevel = "security-level-panel-level-safer"; 202 l10nIdSummary = "security-level-summary-safer"; 203 break; 204 case "safest": 205 l10nIdLevel = "security-level-panel-level-safest"; 206 l10nIdSummary = "security-level-summary-safest"; 207 break; 208 case "custom": 209 l10nIdLevel = "security-level-panel-level-custom"; 210 l10nIdSummary = "security-level-summary-custom"; 211 break; 212 default: 213 throw Error(`Unhandled level: ${level}`); 214 } 215 216 document.l10n.setAttributes(this._elements.levelName, l10nIdLevel); 217 document.l10n.setAttributes(this._elements.summary, l10nIdSummary); 218 }, 219 220 /** 221 * The popup element. 222 * 223 * @type {MozPanel} 224 */ 225 get panel() { 226 if (!this._populated) { 227 this._populateXUL(); 228 } 229 return this._elements.panel; 230 }, 231 232 init() { 233 this._securityPrefsBranch = Services.prefs.getBranch( 234 "browser.security_level." 235 ); 236 this._securityPrefsBranch.addObserver("", this); 237 }, 238 239 uninit() { 240 this._securityPrefsBranch.removeObserver("", this); 241 this._securityPrefsBranch = null; 242 }, 243 244 hide() { 245 this._elements.panel.hidePopup(); 246 }, 247 248 openSecuritySettings() { 249 openPreferences("privacy-securitylevel"); 250 this.hide(); 251 }, 252 253 // callback when prefs change 254 observe(subject, topic, data) { 255 switch (topic) { 256 case "nsPref:changed": 257 if (data == "security_slider" || data == "security_custom") { 258 this._configUIFromPrefs(); 259 } 260 break; 261 } 262 }, 263 }; /* SecurityLevelPanel */ 264 265 /* 266 Security Level Preferences Code 267 268 Code to handle init and update of security level section in about:preferences#privacy 269 */ 270 271 var SecurityLevelPreferences = { 272 _securityPrefsBranch: null, 273 274 /** 275 * The element that shows the current security level. 276 * 277 * @type {?Element} 278 */ 279 _currentEl: null, 280 281 _populateXUL() { 282 this._currentEl = document.getElementById("security-level-current"); 283 const changeButton = document.getElementById("security-level-change"); 284 const badgeEl = this._currentEl.querySelector( 285 ".security-level-current-badge" 286 ); 287 288 for (const { level, nameId } of [ 289 { level: "standard", nameId: "security-level-panel-level-standard" }, 290 { level: "safer", nameId: "security-level-panel-level-safer" }, 291 { level: "safest", nameId: "security-level-panel-level-safest" }, 292 { level: "custom", nameId: "security-level-panel-level-custom" }, 293 ]) { 294 // Classes that control visibility: 295 // security-level-current-standard 296 // security-level-current-safer 297 // security-level-current-safest 298 // security-level-current-custom 299 const visibilityClass = `security-level-current-${level}`; 300 const nameEl = document.createElement("div"); 301 nameEl.classList.add("security-level-name", visibilityClass); 302 document.l10n.setAttributes(nameEl, nameId); 303 304 const descriptionEl = SecurityLevelUIUtils.createDescriptionElement( 305 level, 306 document 307 ); 308 descriptionEl.classList.add(visibilityClass); 309 310 this._currentEl.insertBefore(nameEl, badgeEl); 311 this._currentEl.insertBefore(descriptionEl, changeButton); 312 } 313 314 changeButton.addEventListener("click", () => { 315 this._openDialog(); 316 }); 317 }, 318 319 _openDialog() { 320 gSubDialog.open( 321 "chrome://browser/content/securitylevel/securityLevelDialog.xhtml", 322 { features: "resizable=yes" } 323 ); 324 }, 325 326 _configUIFromPrefs() { 327 // Set a data-current-level attribute for showing the current security 328 // level, and hiding the rest. 329 this._currentEl.dataset.currentLevel = 330 SecurityLevelPrefs.securityLevelSummary; 331 }, 332 333 init() { 334 // populate XUL with localized strings 335 this._populateXUL(); 336 337 // read prefs and populate UI 338 this._configUIFromPrefs(); 339 340 // register for pref chagnes 341 this._securityPrefsBranch = Services.prefs.getBranch( 342 "browser.security_level." 343 ); 344 this._securityPrefsBranch.addObserver("", this); 345 }, 346 347 uninit() { 348 // unregister for pref change events 349 this._securityPrefsBranch.removeObserver("", this); 350 this._securityPrefsBranch = null; 351 }, 352 353 // callback for when prefs change 354 observe(subject, topic, data) { 355 switch (topic) { 356 case "nsPref:changed": 357 if (data == "security_slider" || data == "security_custom") { 358 this._configUIFromPrefs(); 359 } 360 break; 361 } 362 }, 363 }; /* SecurityLevelPreferences */