├── 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 |
--------------------------------------------------------------------------------