├── README.md └── aboutconfig_menu.uc.js /README.md: -------------------------------------------------------------------------------- 1 | # Firefox about:config Menu Shortcut 2 | 3 | Add a menu button on toolbar, which is shortcut to change settings in `about:config`. 4 | 5 | Firefox userChrome script. Tested on Firefox 128. 6 | 7 | ![](https://preview.redd.it/onmgncgvb3j71.png?width=621&format=png&auto=webp&s=b99bab85467a891846da05593b4f9279f70ea789) 8 | 9 | **You should open/edit the code and define your items.** 10 | 11 | Defaultly this script includes: 12 | 13 | - IPv6 enable/disable 14 | - DNS related setting 15 | - Enable deprecated TLS version 16 | - Mouse wheel scroll speed 17 | - Autoplay policy 18 | - WebAudio 19 | - Resisting fingerprint (also webExtension addons recommend: [Toggle Resist Fingerprinting](https://github.com/Aaron-P/ToggleResistFingerprinting) and [Toggle Web Custom Font](https://github.com/garywill/toggleWebCustomFont) ) 20 | - Some locale language related settings 21 | - HTTP referer control ( despite this, recommend webExtension addon [Auto Referer](https://github.com/garywill/autoreferer) ) 22 | - Browser Toolbox connecting confirm 23 | 24 | ---------------- 25 | 26 | This repo only contains the specific function, doesn't contain the code to enable userchrome scripts. 27 | 28 | **For how to enable, see: (also more of my scripts)** 29 | 30 | https://garywill.github.io/#Firefox-userChrome-CSS-or-JS 31 | -------------------------------------------------------------------------------- /aboutconfig_menu.uc.js: -------------------------------------------------------------------------------- 1 | /* Firefox userChrome script 2 | * Shortcut menu to modify about:config entries 3 | * Tested on Firefox 128 4 | * Author: garywill (https://garywill.github.io) 5 | * 6 | */ 7 | 8 | // ==UserScript== 9 | // @include main 10 | // @onlyonce 11 | // ==/UserScript== 12 | 13 | console.log("aboutconfig_menu.uc.js"); 14 | 15 | (() => { 16 | 17 | 18 | const prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService); 19 | Components.utils.import("resource:///modules/CustomizableUI.jsm"); 20 | const Services = globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services; 21 | const sss = Components.classes["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService); 22 | // --------------------------------------------------------------------------------------- 23 | 24 | const button_label = "about:config shortcut menu"; 25 | const cssuri_icon = Services.io.newURI("data:text/css;charset=utf-8," + encodeURIComponent(` 26 | toolbarbutton#aboutconfig-button .toolbarbutton-icon { 27 | list-style-image: url("resource:///chrome/browser/skin/classic/browser/ion.svg"); 28 | } 29 | toolbarbutton#aboutconfig-button .toolbarbutton-badge { 30 | background-color: #009f00; 31 | visibility: hidden; 32 | } 33 | `), null, null); 34 | const cssuri_warnbadge = Services.io.newURI("data:text/css;charset=utf-8," + encodeURIComponent(` 35 | toolbarbutton#aboutconfig-button .toolbarbutton-badge { 36 | background-color: red ; 37 | visibility: unset; 38 | } 39 | `), null, null); 40 | 41 | sss.loadAndRegisterSheet(cssuri_icon, sss.USER_SHEET); 42 | 43 | 44 | var prefItems = [ 45 | { 46 | name: "🌐 Disable IPv6", 47 | type: prefs.PREF_BOOL, 48 | pref: "network.dns.disableIPv6", 49 | possibleVals: [ 50 | { val: false }, 51 | { val: true }, 52 | ] 53 | }, 54 | { 55 | name: "🔐 DNS mode", 56 | type: prefs.PREF_INT, 57 | pref: "network.trr.mode", 58 | possibleVals: [ 59 | { name: "0 - Default" , val: 0 }, 60 | { name: "2 - DoH, fallback Plain DNS" , val: 2 }, 61 | { name: "3 - DoH only" , val: 3 }, 62 | { name: "5 - Plain DNS" , val: 5 } 63 | ] 64 | }, 65 | { 66 | name: "🔐 DoH server", 67 | type: prefs.PREF_STRING, 68 | pref: "network.trr.uri", 69 | possibleVals: [ 70 | { name: "Cloudflare" , val: "https://mozilla.cloudflare-dns.com/dns-query" }, 71 | { name: "NextDNS" , val: "https://firefox.dns.nextdns.io/" } 72 | ] // See buildin DoH at 'network.trr.resolvers' 73 | }, 74 | { 75 | name: "🔏 Enable deprecated TLS version", 76 | type: prefs.PREF_BOOL, 77 | pref: "security.tls.version.enable-deprecated", 78 | possibleVals: [ 79 | { val: false }, 80 | { name: "true ⚠️", val: true , sign: '‼️'}, 81 | ] 82 | }, 83 | 84 | 85 | "seperator", // --------------------------- 86 | { 87 | name: "🖱️ Mouse Wheel Y Multiplier", 88 | type: prefs.PREF_INT, 89 | pref: "mousewheel.default.delta_multiplier_y", 90 | possibleVals: [ 91 | { val: 250 }, 92 | ] 93 | }, 94 | { 95 | name: "🖱️ System scroll vertical factor", 96 | type: prefs.PREF_INT, 97 | pref: "mousewheel.system_scroll_override.vertical.factor", 98 | possibleVals: [ 99 | { val: 250 }, 100 | ] 101 | }, 102 | 103 | 104 | "seperator", // --------------------------- 105 | { 106 | name: "▶️ Media Autoplay Default", 107 | type: prefs.PREF_INT, 108 | pref: "media.autoplay.default", 109 | possibleVals: [ 110 | { val: 0, name: "0 - allow" }, 111 | { val: 1, name: "1 - blockAudible 👍" }, 112 | { val: 5, name: "5 - blockAll" }, 113 | ] 114 | }, 115 | { 116 | name: "▶️ Media Autoplay ext bg", 117 | type: prefs.PREF_BOOL, 118 | pref: "media.autoplay.allow-extension-background-pages", 119 | possibleVals: [ 120 | { val: false }, 121 | { val: true }, 122 | ] 123 | }, 124 | { 125 | name: "▶️ Media Autoplay blocking policy", 126 | type: prefs.PREF_INT, 127 | pref: "media.autoplay.blocking_policy", 128 | possibleVals: [ 129 | { val: 0, name: "0 - no block" }, 130 | { val: 1, name: "1 - block 👍" }, 131 | { val: 2, name: "2 - block more" }, 132 | //* 0=sticky (default), 1=transient, 2=user 133 | ] 134 | }, 135 | { 136 | name: "▶️ WebAudio", 137 | type: prefs.PREF_BOOL, 138 | pref: "dom.webaudio.enabled", 139 | possibleVals: [ 140 | { val: false }, 141 | { val: true , sign: '‼️' , warnbadge: true}, 142 | ] 143 | }, 144 | 145 | "seperator", // --------------------------- 146 | { 147 | name: "🔤 Allow web custom fonts", 148 | type: prefs.PREF_INT, 149 | pref: "browser.display.use_document_fonts", 150 | possibleVals: [ 151 | { name: "1 - Allow", val: 1 }, 152 | { name: "0 - Disallow", val: 0 }, 153 | ] 154 | }, 155 | { 156 | name: "🔤 CSS font visibility", 157 | type: prefs.PREF_INT, 158 | pref: "layout.css.font-visibility.level", 159 | possibleVals: [ 160 | { val: 1, name:"1 - only base system fonts" }, 161 | { val: 2, name:"2 - also fonts from optional language packs" }, 162 | { val: 3, name:"3 - also user-installed fonts" }, 163 | ] 164 | }, 165 | { 166 | name: "🔤 font.system.whitelist", 167 | type: prefs.PREF_STRING, 168 | pref: "font.system.whitelist", 169 | possibleVals: [ 170 | { val: "" }, 171 | { val: "sans, serif, monospace", }, 172 | ] 173 | }, 174 | 175 | "seperator", // --------------------------- 176 | { 177 | name: "🛡️ Resist Fingerprinting", 178 | type: prefs.PREF_BOOL, 179 | pref: "privacy.resistFingerprinting", 180 | possibleVals: [ 181 | { val: false }, 182 | { val: true }, 183 | ] 184 | }, 185 | { 186 | name: "🛡️ Resist Fingerprinting Auto Decline NoUserInput Canvas", 187 | type: prefs.PREF_BOOL, 188 | pref: "privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts", 189 | possibleVals: [ 190 | { val: false }, 191 | { val: true }, 192 | ] 193 | }, 194 | { 195 | name: "🛡️ Resist Fingerprinting LetterBoxing", 196 | type: prefs.PREF_BOOL, 197 | pref: "privacy.resistFingerprinting.letterboxing", 198 | possibleVals: [ 199 | { val: false }, 200 | { val: true }, 201 | ], 202 | }, 203 | 204 | "seperator", // --------------------------- 205 | { 206 | name: "🔤 Accept Languages", 207 | type: prefs.PREF_STRING, 208 | pref: "intl.accept_languages", 209 | possibleVals: [ 210 | { name: "en-US, en", val: "en-US, en" }, 211 | ] 212 | }, 213 | { 214 | name: "🔤 Font Language Group", 215 | type: prefs.PREF_STRING, 216 | pref: "font.language.group", 217 | possibleVals: [ 218 | { name: "x-western", val: "x-western" }, 219 | // { name: "en-US", val: "en-US" }, // any machine actually uses this ??? 220 | ] 221 | }, 222 | { 223 | name: "🔤 JS use English locale", 224 | type: prefs.PREF_BOOL, 225 | pref: "javascript.use_us_english_locale", 226 | possibleVals: [ 227 | { val: false }, 228 | { val: true }, 229 | ] 230 | }, 231 | 232 | 233 | "seperator", // --------------------------- 234 | // https://wiki.mozilla.org/Security/Referrer 235 | { 236 | name: "🛡️ Default Referrer Policy", 237 | type: prefs.PREF_INT, 238 | pref: "network.http.referer.defaultPolicy", 239 | possibleVals: [ 240 | { name: "0 - no-referrer", val: 0 }, 241 | { name: "1 - same-origin", val: 1 }, 242 | { name: "2 - strict-origin-when-cross-origin", val: 2 }, 243 | { name: "3 - no-referrer-when-downgrade", val: 3 }, 244 | 245 | ] 246 | }, 247 | { 248 | name: "🛡️ Referrer Across Origins", 249 | type: prefs.PREF_INT, 250 | pref: "network.http.referer.XOriginPolicy", 251 | possibleVals: [ 252 | { name: "0 - send the referrer in all cases", val: 0 }, 253 | { name: "1 - send a referrer only when the base domains are the same", val: 1 }, 254 | { name: "2 - send a referrer only on same-origin", val: 2 }, 255 | ] 256 | }, 257 | { 258 | name: "🛡️ How much referrer to send regardless of origin", 259 | type: prefs.PREF_INT, 260 | pref: "network.http.referer.trimmingPolicy", 261 | possibleVals: [ 262 | { name: "0 - send the full URL", val: 0 }, 263 | { name: "1 - send the URL without its query string", val: 1 }, 264 | { name: "2 - only send the origin", val: 2 }, 265 | ] 266 | }, 267 | { 268 | name: "🛡️ How much referrer to send across origins", 269 | type: prefs.PREF_INT, 270 | pref: "network.http.referer.XOriginTrimmingPolicy", 271 | possibleVals: [ 272 | { name: "0 - send the full URL", val: 0 }, 273 | { name: "1 - send the URL without its query string", val: 1 }, 274 | { name: "2 - only send the origin", val: 2 }, 275 | ] 276 | }, 277 | "seperator", // --------------------------- 278 | { 279 | name: "💻 DevTool comfirm on connection", 280 | type: prefs.PREF_BOOL, 281 | pref: "devtools.debugger.prompt-connection", 282 | possibleVals: [ 283 | { val: true }, 284 | { name: "false ⚠️", val: false , sign: '‼️' }, 285 | ] 286 | }, 287 | ]; 288 | 289 | CustomizableUI.createWidget({ 290 | id: 'aboutconfig-button', // button id 291 | type: "custom", 292 | defaultArea: CustomizableUI.AREA_NAVBAR, 293 | removable: true, 294 | onBuild: function (doc) { 295 | let btn = doc.createXULElement('toolbarbutton'); 296 | btn.id = 'aboutconfig-button'; 297 | btn.label = button_label; 298 | btn.tooltipText = button_label; 299 | btn.type = 'menu'; 300 | btn.className = 'toolbarbutton-1 chromeclass-toolbar-additional'; 301 | btn.setAttribute("badged", "true"); 302 | btn.setAttribute("badge", "!"); 303 | 304 | let mp = doc.createXULElement("menupopup"); 305 | mp.id = 'aboutconfig-popup'; 306 | mp.onclick = function(event) { event.preventDefault() ;} ; 307 | 308 | 309 | 310 | prefItems.forEach( function (item, items_i) { // loop every user defined pref 311 | 312 | if (item === "seperator") 313 | { 314 | mp.appendChild(doc.createXULElement('menuseparator')); 315 | return; 316 | } 317 | 318 | //var current_val = getItemCurrentVal(item) ; 319 | var menu = doc.createXULElement("menu"); 320 | menu.label = item.name ? item.name : item.pref ; 321 | menu.id = "aboutconfig_menu_" + items_i ; 322 | menu.className = 'menuitem-iconic' ; 323 | 324 | 325 | var menupopup = doc.createXULElement("menupopup"); 326 | menupopup.id = "aboutconfig_menupopup_" + items_i ; 327 | menupopup.className = 'menuitem-iconic' ; 328 | 329 | 330 | 331 | item.possibleVals.forEach( function (pv, i) { // loop every possible value 332 | 333 | var display_val = prefPossibleValToDisplay(item, pv.val) ; 334 | 335 | // Submenu item. One is one possible value 336 | var menuitem = doc.createXULElement("menuitem"); 337 | menuitem.label = pv.name ? pv.name : display_val ; 338 | menuitem.id = "aboutconfig_menu_" + items_i + "__" + i ; 339 | menuitem.setAttribute('type', 'radio') ; 340 | menuitem.className = 'menuitem-iconic' ; 341 | menuitem.tooltipText = display_val ; 342 | 343 | if (pv ['sign']) 344 | menuitem.label += '  ' + pv['sign']; 345 | 346 | 347 | menuitem.addEventListener('click', function(event) { 348 | //console.log(this.id); 349 | setItemPrefVal(item , pv.val); 350 | } ) ; 351 | menupopup.appendChild(menuitem); 352 | 353 | }); 354 | 355 | 356 | 357 | var default_val = getItemDefaultVal(item); 358 | var default_val_display = null; 359 | var reset_label = "Reset: "; 360 | if (item.signWhenDefaultVal) 361 | reset_label += item.signWhenDefaultVal + ' ' ; 362 | if (default_val !== undefined && default_val !== null) 363 | { 364 | default_val_display = prefPossibleValToDisplay(item, default_val); 365 | reset_label += default_val_display ; 366 | } 367 | else 368 | reset_label += ' (delete in about:config)' 369 | 370 | menupopup.appendChild( 371 | doc.createXULElement('menuseparator') 372 | ); 373 | 374 | // Submenu entry to reset a pref to default 375 | var default_item = doc.createXULElement("menuitem"); 376 | default_item.id = "aboutconfig_menu_" + items_i + "__default" ; 377 | default_item.className = 'menuitem-iconic'; 378 | default_item.label = reset_label; 379 | default_item.tooltipText = default_val_display; 380 | 381 | default_item.addEventListener('click', function(event) { 382 | //console.log(this.id); 383 | //setItemPrefVal(item , getItemDefaultVal(item) ); 384 | prefs.clearUserPref(item.pref); 385 | } ) ; 386 | 387 | menupopup.appendChild(default_item); 388 | 389 | //------------ 390 | menu.appendChild(menupopup); 391 | mp.appendChild(menu); 392 | 393 | 394 | }); 395 | 396 | btn.appendChild(mp); 397 | 398 | mp.addEventListener('popupshowing', function() { 399 | //console.log(this); 400 | evalPopulateMenu(this); 401 | 402 | update_badge(); 403 | 404 | }); 405 | 406 | btn.onclick = function(event) { 407 | if (event.button == 1) { 408 | const win = Components.classes["@mozilla.org/appshell/window-mediator;1"] 409 | .getService(Components.interfaces.nsIWindowMediator) 410 | .getMostRecentWindow("navigator:browser"); 411 | win.gBrowser.selectedTab = win.gBrowser.addTrustedTab('about:config'); 412 | } 413 | 414 | update_badge(); 415 | }; 416 | 417 | return btn; 418 | } 419 | }); 420 | 421 | function getItemDefaultVal (item) { 422 | var default_val = undefined; 423 | try{ 424 | if ( item.type == prefs.PREF_BOOL ) 425 | default_val = prefs.getDefaultBranch(item.pref).getBoolPref(''); 426 | else if ( item.type == prefs.PREF_INT ) 427 | default_val = prefs.getDefaultBranch(item.pref).getIntPref(''); 428 | else if ( item.type == prefs.PREF_STRING ) 429 | default_val = prefs.getDefaultBranch(item.pref).getStringPref(''); 430 | }catch(err) { default_val = null } 431 | 432 | return default_val; 433 | } 434 | function getItemCurrentVal (item) { 435 | var current_val = null; 436 | try{ 437 | if ( item.type == prefs.PREF_BOOL ) 438 | current_val = prefs.getBoolPref(item.pref); 439 | else if ( item.type == prefs.PREF_INT ) 440 | current_val = prefs.getIntPref(item.pref); 441 | else if ( item.type == prefs.PREF_STRING ) 442 | current_val = prefs.getStringPref(item.pref); 443 | }catch(err){ } 444 | return current_val ; 445 | } 446 | 447 | function if_pref_current_val_is (item, pv_index) { 448 | var current_val = getItemCurrentVal(item) ; 449 | if (current_val === null) 450 | return false; 451 | 452 | if ( current_val === item.possibleVals[pv_index].val ) 453 | return true; 454 | else 455 | return false; 456 | } 457 | 458 | function setItemPrefVal(item, newVal) 459 | { 460 | if ( item.type == prefs.PREF_BOOL ) 461 | prefs.setBoolPref(item.pref, newVal); 462 | else if ( item.type == prefs.PREF_INT ) 463 | prefs.setIntPref(item.pref, newVal); 464 | else if ( item.type == prefs.PREF_STRING ) 465 | prefs.setStringPref(item.pref, newVal); 466 | 467 | update_badge(); 468 | } 469 | function prefPossibleValToDisplay(item, possible_val ) { 470 | if (possible_val === null) 471 | return "null"; 472 | 473 | var display_val = possible_val.toString(); 474 | if (item.type == prefs.PREF_STRING) 475 | display_val = `'${display_val}'`; 476 | 477 | return display_val; 478 | } 479 | 480 | function evalPopulateMenu(popupmenu) 481 | { 482 | prefItems.forEach( function (item, items_i) { 483 | if (item === "seperator") 484 | return; 485 | 486 | const menu = popupmenu.querySelector("#aboutconfig_menu_" + items_i); 487 | menu.label = item.name ? item.name : item.pref ; 488 | menu.style.fontWeight = ""; 489 | 490 | const default_val = getItemDefaultVal(item); 491 | 492 | var current_val = getItemCurrentVal(item) ; 493 | var current_val_display = prefPossibleValToDisplay(item, current_val); 494 | menu.tooltipText = `Pref: ${item.pref}\nValue: ${current_val_display}`; 495 | 496 | if (current_val !== null) 497 | { 498 | if (item.type == prefs.PREF_BOOL) 499 | menu.label += '  [' + ( current_val?'T':'F' ) + ']'; 500 | else if (item.type == prefs.PREF_INT) 501 | menu.label += '  [' + current_val + ']'; 502 | else if (item.type == prefs.PREF_STRING) { 503 | var current_val_display_short; 504 | 505 | if (current_val.length > 8) 506 | current_val_display_short = current_val.substring(0, 6) + '..'; 507 | else 508 | current_val_display_short = current_val; 509 | 510 | menu.label += '  [' + current_val_display_short + ']'; 511 | } 512 | } 513 | 514 | if (current_val !== default_val) 515 | menu.style.fontWeight = "bold"; 516 | 517 | if (current_val === default_val && item.signWhenDefaultVal) 518 | menu.label += '  ' + item.signWhenDefaultVal; 519 | 520 | 521 | item.possibleVals.forEach( function (pv, i) { 522 | menuitem = popupmenu.querySelector("#aboutconfig_menu_" + items_i + "__" + i); 523 | if ( if_pref_current_val_is(item, i) ) 524 | { 525 | menuitem.setAttribute("checked",true); 526 | 527 | if (pv ['sign']) 528 | menu.label += '  ' + pv['sign']; 529 | } 530 | else 531 | menuitem.setAttribute("checked",false); 532 | }); 533 | }); 534 | } 535 | 536 | function add_warnbadge() 537 | { 538 | if ( ! sss.sheetRegistered(cssuri_warnbadge, sss.USER_SHEET) ) 539 | sss.loadAndRegisterSheet(cssuri_warnbadge, sss.USER_SHEET); 540 | } 541 | function rm_warnbadge() 542 | { 543 | if ( sss.sheetRegistered(cssuri_warnbadge, sss.USER_SHEET) ) 544 | sss.unregisterSheet(cssuri_warnbadge, sss.USER_SHEET); 545 | } 546 | 547 | update_badge(); 548 | async function update_badge() 549 | { 550 | 551 | var show_warnbadge = false; 552 | 553 | for (item of prefItems) 554 | { 555 | if (typeof(item) === "string") 556 | continue; 557 | 558 | const current_val = getItemCurrentVal(item) ; 559 | if ( 560 | item.possibleVals.some ( function(ele) { 561 | return ( ele ['val'] === current_val && ele ['warnbadge'] && ele ['warnbadge'] === true ); 562 | } ) 563 | ) 564 | { 565 | show_warnbadge = true; 566 | break; 567 | } 568 | } 569 | 570 | 571 | if (show_warnbadge) 572 | add_warnbadge(); 573 | else 574 | rm_warnbadge(); 575 | } 576 | 577 | 578 | })(); 579 | 580 | --------------------------------------------------------------------------------