forked from mirrors/gecko-dev
		
	 fcb1b42e8d
			
		
	
	
		fcb1b42e8d
		
	
	
	
	
		
			
			This feature is currently disabled behind a pref, but this pref will be removed when we're green to release it. MozReview-Commit-ID: 3ZH2UJVdtC0 --HG-- rename : browser/components/newtab/tests/browser/.eslintrc.js => browser/components/enterprisepolicies/tests/browser/.eslintrc.js
		
			
				
	
	
		
			358 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			358 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| const Ci = Components.interfaces;
 | |
| const Cc = Components.classes;
 | |
| const Cr = Components.results;
 | |
| const Cu = Components.utils;
 | |
| 
 | |
| Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 | |
| Cu.import("resource://gre/modules/Services.jsm");
 | |
| Cu.import("resource://gre/modules/AppConstants.jsm");
 | |
| 
 | |
| XPCOMUtils.defineLazyModuleGetters(this, {
 | |
|   NetUtil: "resource://gre/modules/NetUtil.jsm",
 | |
|   Policies: "resource:///modules/policies/Policies.jsm",
 | |
|   PoliciesValidator: "resource:///modules/policies/PoliciesValidator.jsm",
 | |
| });
 | |
| 
 | |
| // This is the file that will be searched for in the
 | |
| // ${InstallDir}/distribution folder.
 | |
| const POLICIES_FILENAME = "policies.json";
 | |
| 
 | |
| // For easy testing, modify the helpers/sample.json file,
 | |
| // and set PREF_ALTERNATE_PATH in firefox.js as:
 | |
| // /your/repo/browser/components/enterprisepolicies/helpers/sample.json
 | |
| const PREF_ALTERNATE_PATH     = "browser.policies.alternatePath";
 | |
| 
 | |
| // This pref is meant to be temporary: it will only be used while we're
 | |
| // testing this feature without rolling it out officially. When the
 | |
| // policy engine is released, this pref should be removed.
 | |
| const PREF_ENABLED            = "browser.policies.enabled";
 | |
| const PREF_LOGLEVEL           = "browser.policies.loglevel";
 | |
| 
 | |
| XPCOMUtils.defineLazyGetter(this, "log", () => {
 | |
|   let { ConsoleAPI } = Cu.import("resource://gre/modules/Console.jsm", {});
 | |
|   return new ConsoleAPI({
 | |
|     prefix: "Enterprise Policies",
 | |
|     // tip: set maxLogLevel to "debug" and use log.debug() to create detailed
 | |
|     // messages during development. See LOG_LEVELS in Console.jsm for details.
 | |
|     maxLogLevel: "error",
 | |
|     maxLogLevelPref: PREF_LOGLEVEL,
 | |
|   });
 | |
| });
 | |
| 
 | |
| // ==== Start XPCOM Boilerplate ==== \\
 | |
| 
 | |
| // Factory object
 | |
| const EnterprisePoliciesFactory = {
 | |
|   _instance: null,
 | |
|   createInstance: function BGSF_createInstance(outer, iid) {
 | |
|     if (outer != null)
 | |
|       throw Components.results.NS_ERROR_NO_AGGREGATION;
 | |
|     return this._instance == null ?
 | |
|       this._instance = new EnterprisePoliciesManager() : this._instance;
 | |
|   }
 | |
| };
 | |
| 
 | |
| // ==== End XPCOM Boilerplate ==== //
 | |
| 
 | |
| // Constructor
 | |
| function EnterprisePoliciesManager() {
 | |
|   Services.obs.addObserver(this, "profile-after-change", true);
 | |
|   Services.obs.addObserver(this, "final-ui-startup", true);
 | |
|   Services.obs.addObserver(this, "sessionstore-windows-restored", true);
 | |
|   Services.obs.addObserver(this, "EnterprisePolicies:Restart", true);
 | |
| }
 | |
| 
 | |
| EnterprisePoliciesManager.prototype = {
 | |
|   // for XPCOM
 | |
|   classID:          Components.ID("{ea4e1414-779b-458b-9d1f-d18e8efbc145}"),
 | |
|   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
 | |
|                                          Ci.nsISupportsWeakReference,
 | |
|                                          Ci.nsIEnterprisePolicies]),
 | |
| 
 | |
|   // redefine the default factory for XPCOMUtils
 | |
|   _xpcom_factory: EnterprisePoliciesFactory,
 | |
| 
 | |
|   _initialize() {
 | |
|     if (!Services.prefs.getBoolPref(PREF_ENABLED, false)) {
 | |
|       this.status = Ci.nsIEnterprisePolicies.INACTIVE;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     this._file = new JSONFileReader(getConfigurationFile());
 | |
|     this._file.readData();
 | |
| 
 | |
|     if (!this._file.exists) {
 | |
|       this.status = Ci.nsIEnterprisePolicies.INACTIVE;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (this._file.failed) {
 | |
|       this.status = Ci.nsIEnterprisePolicies.FAILED;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     this.status = Ci.nsIEnterprisePolicies.ACTIVE;
 | |
|     this._activatePolicies();
 | |
|   },
 | |
| 
 | |
|   _activatePolicies() {
 | |
|     let { schema } = Cu.import("resource:///modules/policies/schema.jsm", {});
 | |
|     let json = this._file.json;
 | |
| 
 | |
|     for (let policyName of Object.keys(json.policies)) {
 | |
|       let policySchema = schema.properties[policyName];
 | |
|       let policyParameters = json.policies[policyName];
 | |
| 
 | |
|       if (!policySchema) {
 | |
|         log.error(`Unknown policy: ${policyName}`);
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       let [parametersAreValid, parsedParameters] =
 | |
|         PoliciesValidator.validateAndParseParameters(policyParameters,
 | |
|                                                      policySchema);
 | |
| 
 | |
|       if (!parametersAreValid) {
 | |
|         log.error(`Invalid parameters specified for ${policyName}.`);
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       let policyImpl = Policies[policyName];
 | |
| 
 | |
|       for (let timing of Object.keys(this._callbacks)) {
 | |
|         let policyCallback = policyImpl["on" + timing];
 | |
|         if (policyCallback) {
 | |
|           this._schedulePolicyCallback(
 | |
|             timing,
 | |
|             policyCallback.bind(null,
 | |
|                                 this, /* the EnterprisePoliciesManager */
 | |
|                                 parsedParameters));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   _callbacks: {
 | |
|     BeforeAddons: [],
 | |
|     ProfileAfterChange: [],
 | |
|     BeforeUIStartup: [],
 | |
|     AllWindowsRestored: [],
 | |
|   },
 | |
| 
 | |
|   _schedulePolicyCallback(timing, callback) {
 | |
|     this._callbacks[timing].push(callback);
 | |
|   },
 | |
| 
 | |
|   _runPoliciesCallbacks(timing) {
 | |
|     let callbacks = this._callbacks[timing];
 | |
|     while (callbacks.length > 0) {
 | |
|       let callback = callbacks.shift();
 | |
|       try {
 | |
|         callback();
 | |
|       } catch (ex) {
 | |
|         log.error("Error running ", callback, `for ${timing}:`, ex);
 | |
|       }
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   async _restart() {
 | |
|     if (!Cu.isInAutomation) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     DisallowedFeatures = {};
 | |
| 
 | |
|     this._status = Ci.nsIEnterprisePolicies.UNINITIALIZED;
 | |
|     for (let timing of Object.keys(this._callbacks)) {
 | |
|       this._callbacks[timing] = [];
 | |
|     }
 | |
|     delete Services.ppmm.initialProcessData.policies;
 | |
|     Services.ppmm.broadcastAsyncMessage("EnterprisePolicies:Restart", null);
 | |
| 
 | |
|     let { PromiseUtils } = Cu.import("resource://gre/modules/PromiseUtils.jsm",
 | |
|                                      {});
 | |
| 
 | |
|     // Simulate the startup process. This step-by-step is a bit ugly but it
 | |
|     // tries to emulate the same behavior as of a normal startup.
 | |
| 
 | |
|     await PromiseUtils.idleDispatch(() => {
 | |
|       this.observe(null, "policies-startup", null);
 | |
|     });
 | |
| 
 | |
|     await PromiseUtils.idleDispatch(() => {
 | |
|       this.observe(null, "profile-after-change", null);
 | |
|     });
 | |
| 
 | |
|     await PromiseUtils.idleDispatch(() => {
 | |
|       this.observe(null, "final-ui-startup", null);
 | |
|     });
 | |
| 
 | |
|     await PromiseUtils.idleDispatch(() => {
 | |
|       this.observe(null, "sessionstore-windows-restored", null);
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   // nsIObserver implementation
 | |
|   observe: function BG_observe(subject, topic, data) {
 | |
|     switch (topic) {
 | |
|       case "policies-startup":
 | |
|         this._initialize();
 | |
|         this._runPoliciesCallbacks("BeforeAddons");
 | |
|         break;
 | |
| 
 | |
|       case "profile-after-change":
 | |
|         // Before the first set of policy callbacks runs, we must
 | |
|         // initialize the service.
 | |
|         this._runPoliciesCallbacks("ProfileAfterChange");
 | |
|         break;
 | |
| 
 | |
|       case "final-ui-startup":
 | |
|         this._runPoliciesCallbacks("BeforeUIStartup");
 | |
|         break;
 | |
| 
 | |
|       case "sessionstore-windows-restored":
 | |
|         this._runPoliciesCallbacks("AllWindowsRestored");
 | |
| 
 | |
|         // After the last set of policy callbacks ran, notify the test observer.
 | |
|         Services.obs.notifyObservers(null,
 | |
|                                      "EnterprisePolicies:AllPoliciesApplied");
 | |
|         break;
 | |
| 
 | |
|       case "EnterprisePolicies:Restart":
 | |
|         this._restart().then(null, Cu.reportError);
 | |
|         break;
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   disallowFeature(feature, neededOnContentProcess = false) {
 | |
|     DisallowedFeatures[feature] = true;
 | |
| 
 | |
|     // NOTE: For optimization purposes, only features marked as needed
 | |
|     // on content process will be passed onto the child processes.
 | |
|     if (neededOnContentProcess) {
 | |
|       Services.ppmm.initialProcessData.policies
 | |
|                                       .disallowedFeatures.push(feature);
 | |
| 
 | |
|       if (Services.ppmm.childCount > 1) {
 | |
|         // If there has been a content process already initialized, let's
 | |
|         // broadcast the newly disallowed feature.
 | |
|         Services.ppmm.broadcastAsyncMessage(
 | |
|           "EnterprisePolicies:DisallowFeature", {feature}
 | |
|         );
 | |
|       }
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   // ------------------------------
 | |
|   // public nsIEnterprisePolicies members
 | |
|   // ------------------------------
 | |
| 
 | |
|   _status: Ci.nsIEnterprisePolicies.UNINITIALIZED,
 | |
| 
 | |
|   set status(val) {
 | |
|     this._status = val;
 | |
|     if (val != Ci.nsIEnterprisePolicies.INACTIVE) {
 | |
|       Services.ppmm.initialProcessData.policies = {
 | |
|         status: val,
 | |
|         disallowedFeatures: [],
 | |
|       };
 | |
|     }
 | |
|     return val;
 | |
|   },
 | |
| 
 | |
|   get status() {
 | |
|     return this._status;
 | |
|   },
 | |
| 
 | |
|   isAllowed: function BG_sanitize(feature) {
 | |
|     return !(feature in DisallowedFeatures);
 | |
|   },
 | |
| };
 | |
| 
 | |
| let DisallowedFeatures = {};
 | |
| 
 | |
| function JSONFileReader(file) {
 | |
|   this._file = file;
 | |
|   this._data = {
 | |
|     exists: null,
 | |
|     failed: false,
 | |
|     json: null,
 | |
|   };
 | |
| }
 | |
| 
 | |
| JSONFileReader.prototype = {
 | |
|   get exists() {
 | |
|     if (this._data.exists === null) {
 | |
|       this.readData();
 | |
|     }
 | |
| 
 | |
|     return this._data.exists;
 | |
|   },
 | |
| 
 | |
|   get failed() {
 | |
|     return this._data.failed;
 | |
|   },
 | |
| 
 | |
|   get json() {
 | |
|     if (this._data.failed) {
 | |
|       return null;
 | |
|     }
 | |
| 
 | |
|     if (this._data.json === null) {
 | |
|       this.readData();
 | |
|     }
 | |
| 
 | |
|     return this._data.json;
 | |
|   },
 | |
| 
 | |
|   readData() {
 | |
|     try {
 | |
|       let data = Cu.readUTF8File(this._file);
 | |
|       if (data) {
 | |
|         this._data.exists = true;
 | |
|         this._data.json = JSON.parse(data);
 | |
|       } else {
 | |
|         this._data.exists = false;
 | |
|       }
 | |
|     } catch (ex) {
 | |
|       if (ex instanceof Components.Exception &&
 | |
|           ex.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
 | |
|         this._data.exists = false;
 | |
|       } else if (ex instanceof SyntaxError) {
 | |
|         log.error("Error parsing JSON file");
 | |
|         this._data.failed = true;
 | |
|       } else {
 | |
|         log.error("Error reading file");
 | |
|         this._data.failed = true;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| function getConfigurationFile() {
 | |
|   let configFile = Services.dirsvc.get("XREAppDist", Ci.nsIFile);
 | |
|   configFile.append(POLICIES_FILENAME);
 | |
| 
 | |
|   let prefType = Services.prefs.getPrefType(PREF_ALTERNATE_PATH);
 | |
| 
 | |
|   if ((prefType == Services.prefs.PREF_STRING) && !configFile.exists()) {
 | |
|     // We only want to use the alternate file path if the file on the install
 | |
|     // folder doesn't exist. Otherwise it'd be possible for a user to override
 | |
|     // the admin-provided policies by changing the user-controlled prefs.
 | |
|     // This pref is only meant for tests, so it's fine to use this extra
 | |
|     // synchronous configFile.exists() above.
 | |
|     configFile = Cc["@mozilla.org/file/local;1"]
 | |
|                    .createInstance(Ci.nsIFile);
 | |
|     let alternatePath = Services.prefs.getStringPref(PREF_ALTERNATE_PATH);
 | |
|     configFile.initWithPath(alternatePath);
 | |
|   }
 | |
| 
 | |
|   return configFile;
 | |
| }
 | |
| 
 | |
| var components = [EnterprisePoliciesManager];
 | |
| this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
 |