├── LICENSE ├── README.md ├── autoconfig.js ├── test.cfg └── user.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Theemim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Autoconfig 2 | 3 | Autoconfig is a mechanism that can be used to configure Firefox, Thunderbird, SeaMonkey, and other Gecko-based applications. An autoconfig file is a Javascript file that can modify preferences (application settings) through function calls, and perform other operations, during program startup. It is somewhat similar to the better known user.js file, but there are important differences between the two: 4 | 5 | |Characteristic|autoconfig|user.js| 6 | |:-------------|:---------|:------| 7 | |File location:|Program directory|Profile| 8 | |File modification:|Typically requires admin/elevated credentials|Typically requires user credentials| 9 | |Can affect:|All profiles|The profile where it resides| 10 | |Function API:| * getPrefBranch()
* pref(prefName, value)
* defaultPref(prefName, value)
* lockPref(prefName, value)
* lockPref(prefName)
* getPref(prefName)
* clearPref(prefName)
* setLDAPVersion(version)
* getLDAPAttributes(host, base, filter, attribs, isSecure)
* getLDAPValue(str, key)
* displayError(funcname, message)
* getenv(name)|* user_pref(prefName, value)
* pref(prefName, value)
* sticky_pref(prefName, value)| 11 | |Javascript:|Most language features supported|File parser will only process the above function calls| 12 | |Error handling:|Exceptions, error dialogs, custom logging possibilities|Typically silent aborting of file processing| 13 | |Can use other browser APIs via XPCOM[1](#f1):|Yes|No| 14 | |Can be interactive:|Yes|No| 15 | |Can override and restrict user modifications:|Yes|No| 16 | |Geared toward:|Organizations, admin, users who want its additional capabilities|Those wanting simpler, inherently per-profile, pref setting capabilities| 17 | 18 | Due to the differences in function calls and other aspects, an autoconfig file and user.js are not interchangeable. Nor are they mutually exclusive. Both can be used at the same time. It is worth noting that they can perform similar preference modifications, and converting those calls may only involve changing the name of the function used. So someone prefering autoconfig may leverage user.js examples, and vice versa. 19 | 20 | Most pages about autoconfig were created in the past and have not been kept up to date. Many examples refer to preferences and/or other things which are no longer applicable. However, the basic characteristics of autoconfig (such as the function call interface it uses) have been pretty stable. So even the oldest articles continue to have some relevancy. 21 | 22 | If you are interested in this subject, I would suggest that you start with Mike Kaply's articles. Plus, play around in a test environment. Try manipulating prefs in different ways. Then check the results by reading prefs and viewing what appears in about:config and prefs.js. The autoconfig.js, test.cfg, and user.js files here are intended for such experimentation. 23 | 24 | #### Mike Kaply Articles 25 | * [Firefox Autoconfig Files](https://mike.kaply.com/2012/03/16/customizing-firefox-autoconfig-files) 26 | * [Firefox Autoconfig Files Continued](https://mike.kaply.com/2012/03/20/customizing-firefox-autoconfig-files-continued/) 27 | * [Advanced Autoconfig Files](https://mike.kaply.com/2012/03/22/customizing-firefox-advanced-autoconfig-files/) 28 | * [Debugging Firefox Autoconfig Problems](https://mike.kaply.com/2016/09/08/debugging-firefox-autoconfig-problems/) 29 | 30 | #### Mozilla Autoconfig Related 31 | * [Mission Control Desktop AKA AutoConfig](https://developer.mozilla.org/docs/MCD,_Mission_Control_Desktop_AKA_AutoConfig) 32 | * [A brief guide to Mozilla preferences](https://developer.mozilla.org/docs/Mozilla/Preferences/A_brief_guide_to_Mozilla_preferences) 33 | * [Deploying Firefox in an Enterprise Environment](https://developer.mozilla.org/Firefox/Enterprise_deployment) 34 | * [Deploying Thunderbird in the Enterprise](https://developer.mozilla.org/docs/Mozilla/Thunderbird/Deploying_Thunderbird_in_the_Enterprise) 35 | 36 | #### Mozilla Source Code 37 | * [/extensions/pref/autoconfig](https://dxr.mozilla.org/mozilla-central/source/extensions/pref/autoconfig/) 38 | * [/modules/libpref](https://dxr.mozilla.org/mozilla-central/source/modules/libpref/) 39 | 40 | #### Mozilla XPCOM Related 41 | * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM 42 | * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface 43 | 44 | #### Dean Brundage Articles 45 | * [An Introduction To Mission Control Desktop](http://blog.deanandadie.net/2010/04/an-introduction-to-mission-control-desktop/) 46 | * [Setting User Preferences with Mission Control Desktop](http://blog.deanandadie.net/2010/04/setting-user-preferences-with-mission-control-desktop/) 47 | * [LDAP Queries in Mission Control Desktop](http://blog.deanandadie.net/2010/04/ldap-queries-in-mission-control-desktop/) 48 | * [Mapping Firefox & Thunderbird Behaviors to Preference Settings](http://blog.deanandadie.net/2010/04/mapping-firefox-thunderbird-behaviors-to-preference-settings/) 49 | * [Reading Local Files With Javascript](http://blog.deanandadie.net/2010/05/reading-local-files-with-javascript/) 50 | * [Manufacturing User Preferences For MCD](http://blog.deanandadie.net/2010/05/manufacturing-user-preferences-for-mcd/) 51 | * [Easy Thunderbird Account Management Using MCD](http://blog.deanandadie.net/2010/06/easy-thunderbird-account-management-using-mcd/) 52 | 53 | #### Other Autoconfig Links 54 | * [http://web.mit.edu/~firefox/www/maintainers/autoconfig.html](http://web.mit.edu/~firefox/www/maintainers/autoconfig.html) 55 | * [http://pascal-mietlicki.fr/en/blog/post/work/firefox-autoconfig/](http://pascal-mietlicki.fr/en/blog/post/work/firefox-autoconfig/) 56 | * [https://wpkg.org/Thunderbird#Thunderbird_Configuration](https://wpkg.org/Thunderbird#Thunderbird_Configuration) 57 | * [http://kb.mozillazine.org/Configuration_utilities_for_administrators](http://kb.mozillazine.org/Configuration_utilities_for_administrators) 58 | * [http://kb.mozillazine.org/Locking_preferences](http://kb.mozillazine.org/Locking_preferences) 59 | 60 | #### Related Links 61 | * [https://github.com/mkaply/cck2wizard](https://github.com/mkaply/cck2wizard) 62 | * [https://github.com/sz-blacky/firefox-gpo](https://github.com/sz-blacky/firefox-gpo) 63 | * [https://github.com/n8felton/Firefox-ADMX](https://github.com/n8felton/Firefox-ADMX) 64 | * [http://www.amsys.co.uk/2015/09/using-firefox-cck2-and-autopkg/](http://www.amsys.co.uk/2015/09/using-firefox-cck2-and-autopkg/) 65 | * [https://github.com/ElektraInitiative/libelektra/blob/master/src/plugins/mozprefs/autoconfig/README.md](https://github.com/ElektraInitiative/libelektra/blob/master/src/plugins/mozprefs/autoconfig/README.md) 66 | * [https://support.securly.com/hc/en-us/articles/215479918-Firefox-SSL-Management](https://support.securly.com/hc/en-us/articles/215479918-Firefox-SSL-Management) 67 | * [https://stackoverflow.com/questions/37553127/is-it-possible-to-automatically-import-certificates-in-firefox](https://stackoverflow.com/questions/37553127/is-it-possible-to-automatically-import-certificates-in-firefox) 68 | 69 | #### User.js Overviews 70 | * [https://github.com/ghacksuserjs/ghacks-user.js/wiki/1.1-Overview](https://github.com/ghacksuserjs/ghacks-user.js/wiki/1.1-Overview) 71 | * [http://kb.mozillazine.org/User.js_file](http://kb.mozillazine.org/User.js_file) 72 | 73 | #### User.js Examples 74 | * https://github.com/ghacksuserjs/ghacks-user.js 75 | * https://github.com/pyllyukko/user.js/ 76 | * https://github.com/atomGit/Firefox-user.js 77 | 78 | --- 79 | 1 The deprecation of XUL/XPCOM addons eliminates the primary external consumer of those APIs. There are plans to remove some of those APIs and rewrite others. That, combined with the relative obscurity of autoconfig and its more telemetry-resistant user base, may lead to some XPCOM utilizing autoconfig files being broken. Those using, or wanting to use, autoconfig should keep this in mind. If there is something you are using, or believe is important to keep, you should get involved on the bugzilla and developer fronts.[↩](#a1) 80 | 81 | -------------------------------------------------------------------------------- /autoconfig.js: -------------------------------------------------------------------------------- 1 | // First line is ignored. Leave a single line comment here. 2 | 3 | pref("general.config.obscure_value", 0); 4 | pref("general.config.filename", "test.cfg"); 5 | -------------------------------------------------------------------------------- /test.cfg: -------------------------------------------------------------------------------- 1 | // First line is ignored. Leave a single line comment here. 2 | 3 | "use strict"; 4 | 5 | var milestone = "0"; 6 | var cfgFile = "Autoconfig"; 7 | try { 8 | cfgFile = getPref("general.config.filename"); 9 | if(typeof(Services) === "undefined") { 10 | Components.utils.import("resource://gre/modules/Services.jsm"); 11 | } 12 | function setMilestone(str) { 13 | milestone = str; 14 | lockPref("__testcfgMilestone", str); 15 | //Services.prompt.alert(null, cfgFile, "Milestone: " + str); 16 | } 17 | setMilestone("1"); 18 | 19 | function createErrorCondition() { 20 | // Throw of new Error 21 | throw(new Error("This is a throw of a new Error")); 22 | 23 | // Throw of string 24 | //throw("This is a throw of a string"); 25 | 26 | // Test non-existent function call 27 | //thisFunctionDoesNotExist(); 28 | 29 | // Wrong arguments 30 | //pref("__testcfg-error1"); 31 | //getPref(); 32 | //getPref(undefined); 33 | 34 | // Setting an int pref to a string 35 | //lockPref("__testcfg-error2", 1); 36 | //lockPref("__testcfg-error2", "FOUND"); 37 | 38 | // Missing semicolon 39 | //lockPref("__testcfg-error3", "FOUND") 40 | 41 | // Missing closing quote 42 | //lockPref("__testcfg-error4, "FOUND"); 43 | 44 | // Extra paren 45 | //lockPref("__testcfg-error5", "FOUND")); 46 | 47 | // Unmatched closing brace 48 | // } 49 | } 50 | var testPrefs = [ 51 | // __testcfgMilestone 52 | "__testcfg-error1", 53 | "__testcfg-error2", 54 | "__testcfg-error3", 55 | "__testcfg-error4", 56 | "__testcfg-error5", 57 | "__testcfg-setwith-pref", 58 | "__testcfg-setwith-defaultPref", 59 | "__testcfg-setwith-lockPref", 60 | //__userjsMilestone 61 | "__userjs-error1", 62 | "__userjs-error2", 63 | "__userjs-error3", 64 | "__userjs-error4", 65 | "__userjs-error5", 66 | "__userjs-setwith-user_pref", 67 | "__userjs-setwith-pref", 68 | "__userjs-setwith-sticky_pref", 69 | ]; 70 | function getTestPrefsStr() { 71 | var str = "Current state of test prefs:\n\n"; 72 | testPrefs.forEach(function(prefName) { 73 | str += prefName + " : " + getPref(prefName) + "\n"; 74 | }); 75 | return(str + "\n"); 76 | } 77 | function buttonPrompt(title, msg, button0Title, button1Title, button2Title) { 78 | // Due to bug 345067, this will always return 1 if the user closes the window 79 | // using the close button in the titlebar. Behavior of this function: button1 80 | // is non-optional, it will always be the default, if it is clicked or a close 81 | // happens then the return code will be 1. A return code of 1 should be a safe 82 | // "do nothing" choice. Other buttons are optional. If only two buttons are 83 | // needed use button0 and button1. Button positions may be platform dependent. 84 | // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIPromptService#confirmEx() 85 | // https://bugzilla.mozilla.org/show_bug.cgi?id=345067 86 | if(!button1Title) { 87 | throw(new Error("button1 is not optional")); 88 | } 89 | if(!button0Title && button2Title) { 90 | throw(new Error("For two button prompts use button0 and button1")); 91 | } 92 | var buttonFlags; 93 | var promptSvc = Services.prompt; 94 | if(!button0Title && !button2Title) { 95 | // Adjustment due to button1 handling 96 | button0Title = button1Title; 97 | button1Title = null; 98 | buttonFlags = (promptSvc.BUTTON_POS_0 * promptSvc.BUTTON_TITLE_IS_STRING) + 99 | promptSvc.BUTTON_POS_0_DEFAULT; 100 | } 101 | else { 102 | buttonFlags = (promptSvc.BUTTON_POS_1 * promptSvc.BUTTON_TITLE_IS_STRING) + 103 | promptSvc.BUTTON_POS_1_DEFAULT; 104 | if(button0Title) { 105 | buttonFlags += (promptSvc.BUTTON_POS_0 * promptSvc.BUTTON_TITLE_IS_STRING); 106 | } 107 | if(button2Title) { 108 | buttonFlags += (promptSvc.BUTTON_POS_2 * promptSvc.BUTTON_TITLE_IS_STRING); 109 | } 110 | } 111 | var result = promptSvc.confirmEx(null, title, msg, buttonFlags, button0Title, button1Title, button2Title, null, {}); 112 | if((!button1Title && !button2Title) && (result === 0)) { 113 | // Adjustment due to button1 handling 114 | result = 1; 115 | } 116 | return(result); 117 | } 118 | function getDialogMsg(leader, trailer) { 119 | if(leader) { 120 | leader += "\n\n"; 121 | } 122 | return(leader + getTestPrefsStr() + trailer + "\n\n"); 123 | } 124 | setMilestone("2"); 125 | 126 | var profileDir = Services.dirsvc.get("ProfD", Components.interfaces.nsIFile); 127 | var leader = "Hello " + (getenv("USERNAME") || getenv("USER") || "Human") + "!\n\n" + 128 | "You are working with profile: " + profileDir.leafName; 129 | var msg = getDialogMsg(leader, "Would you like to create an error condition?"); 130 | var buttonPressed = buttonPrompt(cfgFile, msg, "Create error", "Skip", null); 131 | if(buttonPressed === 0) { 132 | createErrorCondition(); 133 | leader = "An error condition was created, so you should not see this"; 134 | } 135 | else leader = ""; 136 | setMilestone("3"); 137 | 138 | msg = getDialogMsg(leader, "Would you like to set testcfg prefs?"); 139 | buttonPressed = buttonPrompt(cfgFile, msg, "Set testcfg prefs", "Skip", null); 140 | if(buttonPressed === 0) { 141 | pref("__testcfg-setwith-pref", "Set by test.cfg"); 142 | defaultPref("__testcfg-setwith-defaultPref", "Set by test.cfg"); 143 | lockPref("__testcfg-setwith-lockPref", "Set by test.cfg"); 144 | leader = "The testcfg prefs were set."; 145 | } 146 | else leader = ""; 147 | setMilestone("4"); 148 | 149 | msg = getDialogMsg(leader, "Would you like to set userjs prefs?"); 150 | buttonPressed = buttonPrompt(cfgFile, msg, "Set userjs prefs", "Skip", null); 151 | if(buttonPressed === 0) { 152 | msg = getDialogMsg("", "Which function do you want to use to set userjs prefs?"); 153 | buttonPressed = buttonPrompt(cfgFile, msg, "pref()", "lockPref()", "defaultPref()"); 154 | var prefSetFunc; 155 | var prefValue; 156 | if(buttonPressed === 0) { 157 | prefSetFunc = pref; 158 | prefValue = "Set by test.cfg with pref"; 159 | } 160 | else if(buttonPressed === 1) { 161 | prefSetFunc = lockPref; 162 | prefValue = "Set by test.cfg with lockPref"; 163 | } 164 | else { 165 | prefSetFunc = defaultPref; 166 | prefValue = "Set by test.cfg with defaultPref"; 167 | } 168 | prefSetFunc("__userjs-setwith-user_pref", prefValue); 169 | prefSetFunc("__userjs-setwith-pref", prefValue); 170 | prefSetFunc("__userjs-setwith-sticky_pref", prefValue); 171 | leader = "The userjs prefs were set."; 172 | } 173 | setMilestone("5"); 174 | 175 | msg = getDialogMsg(leader, "Would you like to clear all test prefs?"); 176 | buttonPressed = buttonPrompt(cfgFile, msg, "Clear all test prefs", "Skip", null); 177 | if(buttonPressed === 0) { 178 | testPrefs.forEach(function(prefName) { 179 | clearPref(prefName); 180 | }); 181 | leader = "All test prefs were cleared."; 182 | } 183 | else leader = ""; 184 | setMilestone("6"); 185 | 186 | msg = getDialogMsg(leader, "Nothing more to do."); 187 | buttonPrompt(cfgFile, msg, null, "OK", null); 188 | 189 | var consoleSvc = Components.classes["@mozilla.org/consoleservice;1"] 190 | .getService(Components.interfaces.nsIConsoleService); 191 | consoleSvc.logStringMessage(cfgFile + " was here"); 192 | setMilestone("7 (Done)"); 193 | } 194 | catch(e) { 195 | displayError(cfgFile, "\n\n " + e.toString() + "\n Stack: " + e.stack + 196 | "\n Last milestone: " + milestone + "\n"); 197 | throw(""); 198 | } 199 | -------------------------------------------------------------------------------- /user.js: -------------------------------------------------------------------------------- 1 | user_pref("__userjsMilestone", "1"); 2 | 3 | // Test non-existent function call 4 | //thisFunctionDoesNotExist(); 5 | 6 | // Too few arguments 7 | //user_pref("__userjs-error1"); 8 | 9 | // Setting an int pref to a string 10 | //user_pref("__userjs-error2", 1); 11 | //user_pref("__userjs-error2", "this-should-not-be-set"); 12 | 13 | // Missing semicolon 14 | //user_pref("__userjs-error3", "this-should-not-be-set") 15 | 16 | // Missing closing quote 17 | //user_pref("__userjs-error4, "this-should-not-be-set"); 18 | 19 | // Extra paren 20 | //user_pref("__userjs-error5", "this-should-not-be-set")); 21 | 22 | // Unmatched closing brace 23 | // } 24 | 25 | user_pref("__userjsMilestone", "2"); 26 | 27 | user_pref("__userjs-setwith-user_pref", "Set by user.js"); 28 | pref("__userjs-setwith-pref", "Set by user.js"); 29 | sticky_pref("__userjs-setwith-sticky_pref", "Set by user.js"); 30 | 31 | user_pref("__userjsMilestone", "3 (Done)"); 32 | 33 | --------------------------------------------------------------------------------