зеркало из https://github.com/mozilla/gecko-dev.git
1221 строка
38 KiB
JavaScript
1221 строка
38 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/. */
|
|
|
|
"use strict";
|
|
|
|
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
|
|
|
XPCOMUtils.defineLazyServiceGetters(this, {
|
|
gCertDB: ["@mozilla.org/security/x509certdb;1", "nsIX509CertDB"],
|
|
gXulStore: ["@mozilla.org/xul/xulstore;1", "nsIXULStore"],
|
|
});
|
|
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
|
BookmarksPolicies: "resource:///modules/policies/BookmarksPolicies.jsm",
|
|
CustomizableUI: "resource:///modules/CustomizableUI.jsm",
|
|
ProxyPolicies: "resource:///modules/policies/ProxyPolicies.jsm",
|
|
WebsiteFilter: "resource:///modules/policies/WebsiteFilter.jsm",
|
|
});
|
|
|
|
XPCOMUtils.defineLazyGlobalGetters(this, ["File", "FileReader"]);
|
|
|
|
const PREF_LOGLEVEL = "browser.policies.loglevel";
|
|
const BROWSER_DOCUMENT_URL = AppConstants.BROWSER_CHROME_URL;
|
|
|
|
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
|
let { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm");
|
|
return new ConsoleAPI({
|
|
prefix: "Policies.jsm",
|
|
// 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,
|
|
});
|
|
});
|
|
|
|
var EXPORTED_SYMBOLS = ["Policies"];
|
|
|
|
/*
|
|
* ============================
|
|
* = POLICIES IMPLEMENTATIONS =
|
|
* ============================
|
|
*
|
|
* The Policies object below is where the implementation for each policy
|
|
* happens. An object for each policy should be defined, containing
|
|
* callback functions that will be called by the engine.
|
|
*
|
|
* See the _callbacks object in EnterprisePolicies.js for the list of
|
|
* possible callbacks and an explanation of each.
|
|
*
|
|
* Each callback will be called with two parameters:
|
|
* - manager
|
|
* This is the EnterprisePoliciesManager singleton object from
|
|
* EnterprisePolicies.js
|
|
*
|
|
* - param
|
|
* The parameter defined for this policy in policies-schema.json.
|
|
* It will be different for each policy. It could be a boolean,
|
|
* a string, an array or a complex object. All parameters have
|
|
* been validated according to the schema, and no unknown
|
|
* properties will be present on them.
|
|
*
|
|
* The callbacks will be bound to their parent policy object.
|
|
*/
|
|
var Policies = {
|
|
"AppUpdateURL": {
|
|
onBeforeAddons(manager, param) {
|
|
setDefaultPref("app.update.url", param.href);
|
|
},
|
|
},
|
|
|
|
"Authentication": {
|
|
onBeforeAddons(manager, param) {
|
|
if ("SPNEGO" in param) {
|
|
setAndLockPref("network.negotiate-auth.trusted-uris", param.SPNEGO.join(", "));
|
|
}
|
|
if ("Delegated" in param) {
|
|
setAndLockPref("network.negotiate-auth.delegation-uris", param.Delegated.join(", "));
|
|
}
|
|
if ("NTLM" in param) {
|
|
setAndLockPref("network.automatic-ntlm-auth.trusted-uris", param.NTLM.join(", "));
|
|
}
|
|
if ("AllowNonFQDN" in param) {
|
|
if (param.AllowNonFQDN.NTLM) {
|
|
setAndLockPref("network.automatic-ntlm-auth.allow-non-fqdn", param.AllowNonFQDN.NTLM);
|
|
}
|
|
if (param.AllowNonFQDN.SPNEGO) {
|
|
setAndLockPref("network.negotiate-auth.allow-non-fqdn", param.AllowNonFQDN.SPNEGO);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
"BlockAboutAddons": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
blockAboutPage(manager, "about:addons", true);
|
|
}
|
|
},
|
|
},
|
|
|
|
"BlockAboutConfig": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
blockAboutPage(manager, "about:config");
|
|
setAndLockPref("devtools.chrome.enabled", false);
|
|
}
|
|
},
|
|
},
|
|
|
|
"BlockAboutProfiles": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
blockAboutPage(manager, "about:profiles");
|
|
}
|
|
},
|
|
},
|
|
|
|
"BlockAboutSupport": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
blockAboutPage(manager, "about:support");
|
|
}
|
|
},
|
|
},
|
|
|
|
"Bookmarks": {
|
|
onAllWindowsRestored(manager, param) {
|
|
BookmarksPolicies.processBookmarks(param);
|
|
},
|
|
},
|
|
|
|
"CaptivePortal": {
|
|
onBeforeAddons(manager, param) {
|
|
setAndLockPref("network.captive-portal-service.enabled", param);
|
|
},
|
|
},
|
|
|
|
"Certificates": {
|
|
onBeforeAddons(manager, param) {
|
|
if ("ImportEnterpriseRoots" in param) {
|
|
setAndLockPref("security.enterprise_roots.enabled", param.ImportEnterpriseRoots);
|
|
}
|
|
if ("Install" in param) {
|
|
(async () => {
|
|
let dirs = [];
|
|
let platform = AppConstants.platform;
|
|
if (platform == "win") {
|
|
dirs = [
|
|
// Ugly, but there is no official way to get %USERNAME\AppData\Roaming\Mozilla.
|
|
Services.dirsvc.get("XREUSysExt", Ci.nsIFile).parent,
|
|
// Even more ugly, but there is no official way to get %USERNAME\AppData\Local\Mozilla.
|
|
Services.dirsvc.get("DefProfLRt", Ci.nsIFile).parent.parent,
|
|
];
|
|
} else if (platform == "macosx" || platform == "linux") {
|
|
dirs = [
|
|
// These two keys are named wrong. They return the Mozilla directory.
|
|
Services.dirsvc.get("XREUserNativeManifests", Ci.nsIFile),
|
|
Services.dirsvc.get("XRESysNativeManifests", Ci.nsIFile),
|
|
];
|
|
}
|
|
dirs.unshift(Services.dirsvc.get("XREAppDist", Ci.nsIFile));
|
|
for (let certfilename of param.Install) {
|
|
let certfile;
|
|
try {
|
|
certfile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
|
certfile.initWithPath(certfilename);
|
|
} catch (e) {
|
|
for (let dir of dirs) {
|
|
certfile = dir.clone();
|
|
certfile.append(platform == "linux" ? "certificates" : "Certificates");
|
|
certfile.append(certfilename);
|
|
if (certfile.exists()) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
let file;
|
|
try {
|
|
file = await File.createFromNsIFile(certfile);
|
|
} catch (e) {
|
|
log.error(`Unable to find certificate - ${certfilename}`);
|
|
continue;
|
|
}
|
|
let reader = new FileReader();
|
|
reader.onloadend = function() {
|
|
if (reader.readyState != reader.DONE) {
|
|
log.error(`Unable to read certificate - ${certfile.path}`);
|
|
return;
|
|
}
|
|
let cert = reader.result;
|
|
try {
|
|
if (/-----BEGIN CERTIFICATE-----/.test(cert)) {
|
|
gCertDB.addCertFromBase64(pemToBase64(cert), "CTu,CTu,");
|
|
} else {
|
|
gCertDB.addCert(cert, "CTu,CTu,");
|
|
}
|
|
} catch (e) {
|
|
log.error(`Unable to add certificate - ${certfile.path}`);
|
|
}
|
|
};
|
|
reader.readAsBinaryString(file);
|
|
}
|
|
})();
|
|
}
|
|
},
|
|
},
|
|
|
|
"Cookies": {
|
|
onBeforeUIStartup(manager, param) {
|
|
addAllowDenyPermissions("cookie", param.Allow, param.Block);
|
|
|
|
if (param.Block) {
|
|
const hosts = param.Block.map(url => url.hostname).sort().join("\n");
|
|
runOncePerModification("clearCookiesForBlockedHosts", hosts, () => {
|
|
for (let blocked of param.Block) {
|
|
Services.cookies.removeCookiesWithOriginAttributes("{}", blocked.hostname);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (param.Default !== undefined ||
|
|
param.AcceptThirdParty !== undefined ||
|
|
param.RejectTracker !== undefined ||
|
|
param.Locked) {
|
|
const ACCEPT_COOKIES = 0;
|
|
const REJECT_THIRD_PARTY_COOKIES = 1;
|
|
const REJECT_ALL_COOKIES = 2;
|
|
const REJECT_UNVISITED_THIRD_PARTY = 3;
|
|
const REJECT_TRACKER = 4;
|
|
|
|
let newCookieBehavior = ACCEPT_COOKIES;
|
|
if (param.Default !== undefined && !param.Default) {
|
|
newCookieBehavior = REJECT_ALL_COOKIES;
|
|
} else if (param.AcceptThirdParty) {
|
|
if (param.AcceptThirdParty == "never") {
|
|
newCookieBehavior = REJECT_THIRD_PARTY_COOKIES;
|
|
} else if (param.AcceptThirdParty == "from-visited") {
|
|
newCookieBehavior = REJECT_UNVISITED_THIRD_PARTY;
|
|
}
|
|
} else if (param.RejectTracker !== undefined && param.RejectTracker) {
|
|
newCookieBehavior = REJECT_TRACKER;
|
|
}
|
|
|
|
if (param.Locked) {
|
|
setAndLockPref("network.cookie.cookieBehavior", newCookieBehavior);
|
|
} else {
|
|
setDefaultPref("network.cookie.cookieBehavior", newCookieBehavior);
|
|
}
|
|
}
|
|
|
|
const KEEP_COOKIES_UNTIL_EXPIRATION = 0;
|
|
const KEEP_COOKIES_UNTIL_END_OF_SESSION = 2;
|
|
|
|
if (param.ExpireAtSessionEnd !== undefined || param.Locked) {
|
|
let newLifetimePolicy = KEEP_COOKIES_UNTIL_EXPIRATION;
|
|
if (param.ExpireAtSessionEnd) {
|
|
newLifetimePolicy = KEEP_COOKIES_UNTIL_END_OF_SESSION;
|
|
}
|
|
|
|
if (param.Locked) {
|
|
setAndLockPref("network.cookie.lifetimePolicy", newLifetimePolicy);
|
|
} else {
|
|
setDefaultPref("network.cookie.lifetimePolicy", newLifetimePolicy);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableAppUpdate": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("appUpdate");
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableBuiltinPDFViewer": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
setAndLockPref("pdfjs.disabled", true);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableDeveloperTools": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
setAndLockPref("devtools.policy.disabled", true);
|
|
setAndLockPref("devtools.chrome.enabled", false);
|
|
|
|
manager.disallowFeature("devtools");
|
|
blockAboutPage(manager, "about:devtools");
|
|
blockAboutPage(manager, "about:debugging");
|
|
blockAboutPage(manager, "about:devtools-toolbox");
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableFeedbackCommands": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("feedbackCommands");
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableFirefoxAccounts": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
setAndLockPref("identity.fxaccounts.enabled", false);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableFirefoxScreenshots": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
setAndLockPref("extensions.screenshots.disabled", true);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableFirefoxStudies": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("Shield");
|
|
setAndLockPref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr", false);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableForgetButton": {
|
|
onProfileAfterChange(manager, param) {
|
|
if (param) {
|
|
setAndLockPref("privacy.panicButton.enabled", false);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableFormHistory": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
setAndLockPref("browser.formfill.enable", false);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableMasterPasswordCreation": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("createMasterPassword");
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisablePocket": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
setAndLockPref("extensions.pocket.enabled", false);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisablePrivateBrowsing": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("privatebrowsing");
|
|
blockAboutPage(manager, "about:privatebrowsing", true);
|
|
setAndLockPref("browser.privatebrowsing.autostart", false);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableProfileImport": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("profileImport");
|
|
setAndLockPref("browser.newtabpage.activity-stream.migrationExpired", true);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableProfileRefresh": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("profileRefresh");
|
|
setAndLockPref("browser.disableResetPrompt", true);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableSafeMode": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("safeMode");
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableSecurityBypass": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if ("InvalidCertificate" in param) {
|
|
setAndLockPref("security.certerror.hideAddException", param.InvalidCertificate);
|
|
}
|
|
|
|
if ("SafeBrowsing" in param) {
|
|
setAndLockPref("browser.safebrowsing.allowOverride", !param.SafeBrowsing);
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableSetDesktopBackground": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("setDesktopBackground");
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableSystemAddonUpdate": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("SysAddonUpdate");
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisableTelemetry": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param) {
|
|
setAndLockPref("datareporting.healthreport.uploadEnabled", false);
|
|
setAndLockPref("datareporting.policy.dataSubmissionEnabled", false);
|
|
blockAboutPage(manager, "about:telemetry");
|
|
}
|
|
},
|
|
},
|
|
|
|
"DisplayBookmarksToolbar": {
|
|
onBeforeUIStartup(manager, param) {
|
|
let value = (!param).toString();
|
|
// This policy is meant to change the default behavior, not to force it.
|
|
// If this policy was alreay applied and the user chose to re-hide the
|
|
// bookmarks toolbar, do not show it again.
|
|
runOncePerModification("displayBookmarksToolbar", value, () => {
|
|
gXulStore.setValue(BROWSER_DOCUMENT_URL, "PersonalToolbar", "collapsed", value);
|
|
});
|
|
},
|
|
},
|
|
|
|
"DisplayMenuBar": {
|
|
onBeforeUIStartup(manager, param) {
|
|
let value = (!param).toString();
|
|
// This policy is meant to change the default behavior, not to force it.
|
|
// If this policy was alreay applied and the user chose to re-hide the
|
|
// menu bar, do not show it again.
|
|
runOncePerModification("displayMenuBar", value, () => {
|
|
gXulStore.setValue(BROWSER_DOCUMENT_URL, "toolbar-menubar", "autohide", value);
|
|
});
|
|
},
|
|
},
|
|
|
|
"DNSOverHTTPS": {
|
|
onBeforeAddons(manager, param) {
|
|
if ("Enabled" in param) {
|
|
let mode = param.Enabled ? 2 : 5;
|
|
if (param.Locked) {
|
|
setAndLockPref("network.trr.mode", mode);
|
|
} else {
|
|
setDefaultPref("network.trr.mode", mode);
|
|
}
|
|
}
|
|
if (param.ProviderURL) {
|
|
if (param.Locked) {
|
|
setAndLockPref("network.trr.uri", param.ProviderURL.href);
|
|
} else {
|
|
setDefaultPref("network.trr.uri", param.ProviderURL.href);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
"DontCheckDefaultBrowser": {
|
|
onBeforeUIStartup(manager, param) {
|
|
setAndLockPref("browser.shell.checkDefaultBrowser", !param);
|
|
},
|
|
},
|
|
|
|
"EnableTrackingProtection": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param.Value) {
|
|
if (param.Locked) {
|
|
setAndLockPref("privacy.trackingprotection.enabled", true);
|
|
setAndLockPref("privacy.trackingprotection.pbmode.enabled", true);
|
|
} else {
|
|
setDefaultPref("privacy.trackingprotection.enabled", true);
|
|
setDefaultPref("privacy.trackingprotection.pbmode.enabled", true);
|
|
}
|
|
} else {
|
|
setAndLockPref("privacy.trackingprotection.enabled", false);
|
|
setAndLockPref("privacy.trackingprotection.pbmode.enabled", false);
|
|
}
|
|
},
|
|
},
|
|
|
|
"Extensions": {
|
|
onBeforeUIStartup(manager, param) {
|
|
let uninstallingPromise = Promise.resolve();
|
|
if ("Uninstall" in param) {
|
|
uninstallingPromise = runOncePerModification("extensionsUninstall", JSON.stringify(param.Uninstall), async () => {
|
|
// If we're uninstalling add-ons, re-run the extensionsInstall runOnce even if it hasn't
|
|
// changed, which will allow add-ons to be updated.
|
|
Services.prefs.clearUserPref("browser.policies.runOncePerModification.extensionsInstall");
|
|
let addons = await AddonManager.getAddonsByIDs(param.Uninstall);
|
|
for (let addon of addons) {
|
|
if (addon) {
|
|
try {
|
|
await addon.uninstall();
|
|
} catch (e) {
|
|
// This can fail for add-ons that can't be uninstalled.
|
|
// Just ignore.
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if ("Install" in param) {
|
|
runOncePerModification("extensionsInstall", JSON.stringify(param.Install), async () => {
|
|
await uninstallingPromise;
|
|
for (let location of param.Install) {
|
|
let url;
|
|
if (location.includes("://")) {
|
|
// Assume location is an URI
|
|
url = location;
|
|
} else {
|
|
// Assume location is a file path
|
|
let xpiFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
|
try {
|
|
xpiFile.initWithPath(location);
|
|
} catch (e) {
|
|
log.error(`Invalid extension path location - ${location}`);
|
|
continue;
|
|
}
|
|
url = Services.io.newFileURI(xpiFile).spec;
|
|
}
|
|
AddonManager.getInstallForURL(url, {
|
|
telemetryInfo: {source: "enterprise-policy"},
|
|
}).then(install => {
|
|
if (install.addon && install.addon.appDisabled) {
|
|
log.error(`Incompatible add-on - ${location}`);
|
|
install.cancel();
|
|
return;
|
|
}
|
|
let listener = {
|
|
/* eslint-disable-next-line no-shadow */
|
|
onDownloadEnded: (install) => {
|
|
if (install.addon && install.addon.appDisabled) {
|
|
log.error(`Incompatible add-on - ${location}`);
|
|
install.removeListener(listener);
|
|
install.cancel();
|
|
}
|
|
},
|
|
onDownloadFailed: () => {
|
|
install.removeListener(listener);
|
|
log.error(`Download failed - ${location}`);
|
|
},
|
|
onInstallFailed: () => {
|
|
install.removeListener(listener);
|
|
log.error(`Installation failed - ${location}`);
|
|
},
|
|
onInstallEnded: () => {
|
|
install.removeListener(listener);
|
|
log.debug(`Installation succeeded - ${location}`);
|
|
},
|
|
};
|
|
install.addListener(listener);
|
|
install.install();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
if ("Locked" in param) {
|
|
for (let ID of param.Locked) {
|
|
manager.disallowFeature(`modify-extension:${ID}`);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
"ExtensionUpdate": {
|
|
onBeforeAddons(manager, param) {
|
|
if (!param) {
|
|
setAndLockPref("extensions.update.enabled", param);
|
|
}
|
|
},
|
|
},
|
|
|
|
"FlashPlugin": {
|
|
onBeforeUIStartup(manager, param) {
|
|
addAllowDenyPermissions("plugin:flash", param.Allow, param.Block);
|
|
|
|
const FLASH_NEVER_ACTIVATE = 0;
|
|
const FLASH_ASK_TO_ACTIVATE = 1;
|
|
const FLASH_ALWAYS_ACTIVATE = 2;
|
|
|
|
let flashPrefVal;
|
|
if (param.Default === undefined) {
|
|
flashPrefVal = FLASH_ASK_TO_ACTIVATE;
|
|
} else if (param.Default) {
|
|
flashPrefVal = FLASH_ALWAYS_ACTIVATE;
|
|
} else {
|
|
flashPrefVal = FLASH_NEVER_ACTIVATE;
|
|
}
|
|
if (param.Locked) {
|
|
setAndLockPref("plugin.state.flash", flashPrefVal);
|
|
} else if (param.Default !== undefined) {
|
|
setDefaultPref("plugin.state.flash", flashPrefVal);
|
|
}
|
|
},
|
|
},
|
|
|
|
"HardwareAcceleration": {
|
|
onBeforeAddons(manager, param) {
|
|
if (!param) {
|
|
setAndLockPref("layers.acceleration.disabled", true);
|
|
}
|
|
},
|
|
},
|
|
|
|
"Homepage": {
|
|
onBeforeUIStartup(manager, param) {
|
|
// |homepages| will be a string containing a pipe-separated ('|') list of
|
|
// URLs because that is what the "Home page" section of about:preferences
|
|
// (and therefore what the pref |browser.startup.homepage|) accepts.
|
|
if (param.URL) {
|
|
let homepages = param.URL.href;
|
|
if (param.Additional && param.Additional.length > 0) {
|
|
homepages += "|" + param.Additional.map(url => url.href).join("|");
|
|
}
|
|
if (param.Locked) {
|
|
setAndLockPref("browser.startup.homepage", homepages);
|
|
setAndLockPref("pref.browser.homepage.disable_button.current_page", true);
|
|
setAndLockPref("pref.browser.homepage.disable_button.bookmark_page", true);
|
|
setAndLockPref("pref.browser.homepage.disable_button.restore_default", true);
|
|
} else {
|
|
setDefaultPref("browser.startup.homepage", homepages);
|
|
runOncePerModification("setHomepage", homepages, () => {
|
|
Services.prefs.clearUserPref("browser.startup.homepage");
|
|
});
|
|
}
|
|
}
|
|
if (param.StartPage) {
|
|
let prefValue;
|
|
switch (param.StartPage) {
|
|
case "none":
|
|
prefValue = 0;
|
|
break;
|
|
case "homepage":
|
|
prefValue = 1;
|
|
break;
|
|
case "previous-session":
|
|
prefValue = 3;
|
|
break;
|
|
}
|
|
if (param.Locked) {
|
|
setAndLockPref("browser.startup.page", prefValue);
|
|
} else {
|
|
setDefaultPref("browser.startup.page", prefValue);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
"InstallAddonsPermission": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if ("Allow" in param) {
|
|
addAllowDenyPermissions("install", param.Allow, null);
|
|
}
|
|
if ("Default" in param) {
|
|
setAndLockPref("xpinstall.enabled", param.Default);
|
|
if (!param.Default) {
|
|
blockAboutPage(manager, "about:debugging");
|
|
setAndLockPref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr", false);
|
|
manager.disallowFeature("xpinstall");
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
"NetworkPrediction": {
|
|
onBeforeAddons(manager, param) {
|
|
setAndLockPref("network.dns.disablePrefetch", !param);
|
|
setAndLockPref("network.dns.disablePrefetchFromHTTPS", !param);
|
|
},
|
|
},
|
|
|
|
"NoDefaultBookmarks": {
|
|
onProfileAfterChange(manager, param) {
|
|
if (param) {
|
|
manager.disallowFeature("defaultBookmarks");
|
|
}
|
|
},
|
|
},
|
|
|
|
"OfferToSaveLogins": {
|
|
onBeforeUIStartup(manager, param) {
|
|
setAndLockPref("signon.rememberSignons", param);
|
|
},
|
|
},
|
|
|
|
"OverrideFirstRunPage": {
|
|
onProfileAfterChange(manager, param) {
|
|
let url = param ? param.href : "";
|
|
setAndLockPref("startup.homepage_welcome_url", url);
|
|
},
|
|
},
|
|
|
|
"OverridePostUpdatePage": {
|
|
onProfileAfterChange(manager, param) {
|
|
let url = param ? param.href : "";
|
|
setAndLockPref("startup.homepage_override_url", url);
|
|
// The pref startup.homepage_override_url is only used
|
|
// as a fallback when the update.xml file hasn't provided
|
|
// a specific post-update URL.
|
|
manager.disallowFeature("postUpdateCustomPage");
|
|
},
|
|
},
|
|
|
|
"Permissions": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param.Camera) {
|
|
addAllowDenyPermissions("camera", param.Camera.Allow, param.Camera.Block);
|
|
setDefaultPermission("camera", param.Camera);
|
|
}
|
|
|
|
if (param.Microphone) {
|
|
addAllowDenyPermissions("microphone", param.Microphone.Allow, param.Microphone.Block);
|
|
setDefaultPermission("microphone", param.Microphone);
|
|
}
|
|
|
|
if (param.Location) {
|
|
addAllowDenyPermissions("geo", param.Location.Allow, param.Location.Block);
|
|
setDefaultPermission("geo", param.Location);
|
|
}
|
|
|
|
if (param.Notifications) {
|
|
addAllowDenyPermissions("desktop-notification", param.Notifications.Allow, param.Notifications.Block);
|
|
setDefaultPermission("desktop-notification", param.Notifications);
|
|
}
|
|
},
|
|
},
|
|
|
|
"PopupBlocking": {
|
|
onBeforeUIStartup(manager, param) {
|
|
addAllowDenyPermissions("popup", param.Allow, null);
|
|
|
|
if (param.Locked) {
|
|
let blockValue = true;
|
|
if (param.Default !== undefined && !param.Default) {
|
|
blockValue = false;
|
|
}
|
|
setAndLockPref("dom.disable_open_during_load", blockValue);
|
|
} else if (param.Default !== undefined) {
|
|
setDefaultPref("dom.disable_open_during_load", !!param.Default);
|
|
}
|
|
},
|
|
},
|
|
|
|
"Proxy": {
|
|
onBeforeAddons(manager, param) {
|
|
if (param.Locked) {
|
|
manager.disallowFeature("changeProxySettings");
|
|
ProxyPolicies.configureProxySettings(param, setAndLockPref);
|
|
} else {
|
|
ProxyPolicies.configureProxySettings(param, setDefaultPref);
|
|
}
|
|
},
|
|
},
|
|
|
|
"RequestedLocales": {
|
|
onBeforeAddons(manager, param) {
|
|
Services.locale.requestedLocales = param;
|
|
},
|
|
},
|
|
|
|
"SanitizeOnShutdown": {
|
|
onBeforeUIStartup(manager, param) {
|
|
setAndLockPref("privacy.sanitize.sanitizeOnShutdown", param);
|
|
if (param) {
|
|
setAndLockPref("privacy.clearOnShutdown.cache", true);
|
|
setAndLockPref("privacy.clearOnShutdown.cookies", true);
|
|
setAndLockPref("privacy.clearOnShutdown.downloads", true);
|
|
setAndLockPref("privacy.clearOnShutdown.formdata", true);
|
|
setAndLockPref("privacy.clearOnShutdown.history", true);
|
|
setAndLockPref("privacy.clearOnShutdown.sessions", true);
|
|
setAndLockPref("privacy.clearOnShutdown.siteSettings", true);
|
|
setAndLockPref("privacy.clearOnShutdown.offlineApps", true);
|
|
}
|
|
},
|
|
},
|
|
|
|
"SearchBar": {
|
|
onAllWindowsRestored(manager, param) {
|
|
// This policy is meant to change the default behavior, not to force it.
|
|
// If this policy was already applied and the user chose move the search
|
|
// bar, don't move it again.
|
|
runOncePerModification("searchInNavBar", param, () => {
|
|
if (param == "separate") {
|
|
CustomizableUI.addWidgetToArea("search-container", CustomizableUI.AREA_NAVBAR,
|
|
CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1);
|
|
} else if (param == "unified") {
|
|
CustomizableUI.removeWidgetFromArea("search-container");
|
|
}
|
|
});
|
|
},
|
|
},
|
|
|
|
"SearchEngines": {
|
|
onBeforeUIStartup(manager, param) {
|
|
if (param.PreventInstalls) {
|
|
manager.disallowFeature("installSearchEngine", true);
|
|
}
|
|
},
|
|
onAllWindowsRestored(manager, param) {
|
|
Services.search.init().then(async () => {
|
|
if (param.Remove) {
|
|
// Only rerun if the list of engine names has changed.
|
|
await runOncePerModification("removeSearchEngines",
|
|
JSON.stringify(param.Remove),
|
|
async function() {
|
|
for (let engineName of param.Remove) {
|
|
let engine = Services.search.getEngineByName(engineName);
|
|
if (engine) {
|
|
try {
|
|
await Services.search.removeEngine(engine);
|
|
} catch (ex) {
|
|
log.error("Unable to remove the search engine", ex);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if (param.Add) {
|
|
// Only rerun if the list of engine names has changed.
|
|
let engineNameList = param.Add.map(engine => engine.Name);
|
|
await runOncePerModification("addSearchEngines",
|
|
JSON.stringify(engineNameList),
|
|
async function() {
|
|
for (let newEngine of param.Add) {
|
|
let newEngineParameters = {
|
|
template: newEngine.URLTemplate,
|
|
iconURL: newEngine.IconURL ? newEngine.IconURL.href : null,
|
|
alias: newEngine.Alias,
|
|
description: newEngine.Description,
|
|
method: newEngine.Method,
|
|
postData: newEngine.PostData,
|
|
suggestURL: newEngine.SuggestURLTemplate,
|
|
extensionID: "set-via-policy",
|
|
queryCharset: "UTF-8",
|
|
};
|
|
try {
|
|
await Services.search.addEngineWithDetails(newEngine.Name,
|
|
newEngineParameters);
|
|
} catch (ex) {
|
|
log.error("Unable to add search engine", ex);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if (param.Default) {
|
|
await runOncePerModification("setDefaultSearchEngine", param.Default, async () => {
|
|
let defaultEngine;
|
|
try {
|
|
defaultEngine = Services.search.getEngineByName(param.Default);
|
|
if (!defaultEngine) {
|
|
throw "No engine by that name could be found";
|
|
}
|
|
} catch (ex) {
|
|
log.error(`Search engine lookup failed when attempting to set ` +
|
|
`the default engine. Requested engine was ` +
|
|
`"${param.Default}".`, ex);
|
|
}
|
|
if (defaultEngine) {
|
|
try {
|
|
await Services.search.setDefault(defaultEngine);
|
|
} catch (ex) {
|
|
log.error("Unable to set the default search engine", ex);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
},
|
|
},
|
|
|
|
"SecurityDevices": {
|
|
onProfileAfterChange(manager, param) {
|
|
let securityDevices = param;
|
|
let pkcs11db = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(Ci.nsIPKCS11ModuleDB);
|
|
let moduleList = pkcs11db.listModules();
|
|
for (let deviceName in securityDevices) {
|
|
let foundModule = false;
|
|
for (let module of moduleList) {
|
|
if (module && module.libName === securityDevices[deviceName]) {
|
|
foundModule = true;
|
|
break;
|
|
}
|
|
}
|
|
if (foundModule) {
|
|
continue;
|
|
}
|
|
try {
|
|
pkcs11db.addModule(deviceName, securityDevices[deviceName], 0, 0);
|
|
} catch (ex) {
|
|
log.error(`Unable to add security device ${deviceName}`);
|
|
log.debug(ex);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
"SSLVersionMax": {
|
|
onBeforeAddons(manager, param) {
|
|
let tlsVersion;
|
|
switch (param) {
|
|
case "tls1":
|
|
tlsVersion = 1;
|
|
break;
|
|
case "tls1.1":
|
|
tlsVersion = 2;
|
|
break;
|
|
case "tls1.2":
|
|
tlsVersion = 3;
|
|
break;
|
|
case "tls1.3":
|
|
tlsVersion = 4;
|
|
break;
|
|
}
|
|
setAndLockPref("security.tls.version.max", tlsVersion);
|
|
},
|
|
},
|
|
|
|
"SSLVersionMin": {
|
|
onBeforeAddons(manager, param) {
|
|
let tlsVersion;
|
|
switch (param) {
|
|
case "tls1":
|
|
tlsVersion = 1;
|
|
break;
|
|
case "tls1.1":
|
|
tlsVersion = 2;
|
|
break;
|
|
case "tls1.2":
|
|
tlsVersion = 3;
|
|
break;
|
|
case "tls1.3":
|
|
tlsVersion = 4;
|
|
break;
|
|
}
|
|
setAndLockPref("security.tls.version.min", tlsVersion);
|
|
},
|
|
},
|
|
|
|
"SupportMenu": {
|
|
onProfileAfterChange(manager, param) {
|
|
manager.setSupportMenu(param);
|
|
},
|
|
},
|
|
|
|
"WebsiteFilter": {
|
|
onBeforeUIStartup(manager, param) {
|
|
this.filter = new WebsiteFilter(param.Block || [], param.Exceptions || []);
|
|
},
|
|
},
|
|
|
|
};
|
|
|
|
/*
|
|
* ====================
|
|
* = HELPER FUNCTIONS =
|
|
* ====================
|
|
*
|
|
* The functions below are helpers to be used by several policies.
|
|
*/
|
|
|
|
/**
|
|
* setAndLockPref
|
|
*
|
|
* Sets the _default_ value of a pref, and locks it (meaning that
|
|
* the default value will always be returned, independent from what
|
|
* is stored as the user value).
|
|
* The value is only changed in memory, and not stored to disk.
|
|
*
|
|
* @param {string} prefName
|
|
* The pref to be changed
|
|
* @param {boolean,number,string} prefValue
|
|
* The value to set and lock
|
|
*/
|
|
function setAndLockPref(prefName, prefValue) {
|
|
if (Services.prefs.prefIsLocked(prefName)) {
|
|
Services.prefs.unlockPref(prefName);
|
|
}
|
|
|
|
setDefaultPref(prefName, prefValue);
|
|
|
|
Services.prefs.lockPref(prefName);
|
|
}
|
|
|
|
/**
|
|
* setDefaultPref
|
|
*
|
|
* Sets the _default_ value of a pref.
|
|
* The value is only changed in memory, and not stored to disk.
|
|
*
|
|
* @param {string} prefName
|
|
* The pref to be changed
|
|
* @param {boolean,number,string} prefValue
|
|
* The value to set
|
|
*/
|
|
function setDefaultPref(prefName, prefValue) {
|
|
let defaults = Services.prefs.getDefaultBranch("");
|
|
|
|
switch (typeof(prefValue)) {
|
|
case "boolean":
|
|
defaults.setBoolPref(prefName, prefValue);
|
|
break;
|
|
|
|
case "number":
|
|
if (!Number.isInteger(prefValue)) {
|
|
throw new Error(`Non-integer value for ${prefName}`);
|
|
}
|
|
|
|
defaults.setIntPref(prefName, prefValue);
|
|
break;
|
|
|
|
case "string":
|
|
defaults.setStringPref(prefName, prefValue);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* setDefaultPermission
|
|
*
|
|
* Helper function to set preferences appropriately for the policy
|
|
*
|
|
* @param {string} policyName
|
|
* The name of the policy to set
|
|
* @param {object} policyParam
|
|
* The object containing param for the policy
|
|
*/
|
|
function setDefaultPermission(policyName, policyParam) {
|
|
if ("BlockNewRequests" in policyParam) {
|
|
let prefName = "permissions.default." + policyName;
|
|
|
|
if (policyParam.BlockNewRequests) {
|
|
if (policyParam.Locked) {
|
|
setAndLockPref(prefName, 2);
|
|
} else {
|
|
setDefaultPref(prefName, 2);
|
|
}
|
|
} else if (policyParam.Locked) {
|
|
setAndLockPref(prefName, 0);
|
|
} else {
|
|
setDefaultPref(prefName, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* addAllowDenyPermissions
|
|
*
|
|
* Helper function to call the permissions manager (Services.perms.add)
|
|
* for two arrays of URLs.
|
|
*
|
|
* @param {string} permissionName
|
|
* The name of the permission to change
|
|
* @param {array} allowList
|
|
* The list of URLs to be set as ALLOW_ACTION for the chosen permission.
|
|
* @param {array} blockList
|
|
* The list of URLs to be set as DENY_ACTION for the chosen permission.
|
|
*/
|
|
function addAllowDenyPermissions(permissionName, allowList, blockList) {
|
|
allowList = allowList || [];
|
|
blockList = blockList || [];
|
|
|
|
for (let origin of allowList) {
|
|
try {
|
|
Services.perms.add(Services.io.newURI(origin.href),
|
|
permissionName,
|
|
Ci.nsIPermissionManager.ALLOW_ACTION,
|
|
Ci.nsIPermissionManager.EXPIRE_POLICY);
|
|
} catch (ex) {
|
|
log.error(`Added by default for ${permissionName} permission in the permission
|
|
manager - ${origin.href}`);
|
|
}
|
|
}
|
|
|
|
for (let origin of blockList) {
|
|
Services.perms.add(Services.io.newURI(origin.href),
|
|
permissionName,
|
|
Ci.nsIPermissionManager.DENY_ACTION,
|
|
Ci.nsIPermissionManager.EXPIRE_POLICY);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* runOnce
|
|
*
|
|
* Helper function to run a callback only once per policy.
|
|
*
|
|
* @param {string} actionName
|
|
* A given name which will be used to track if this callback has run.
|
|
* @param {Functon} callback
|
|
* The callback to run only once.
|
|
*/
|
|
// eslint-disable-next-line no-unused-vars
|
|
function runOnce(actionName, callback) {
|
|
let prefName = `browser.policies.runonce.${actionName}`;
|
|
if (Services.prefs.getBoolPref(prefName, false)) {
|
|
log.debug(`Not running action ${actionName} again because it has already run.`);
|
|
return;
|
|
}
|
|
Services.prefs.setBoolPref(prefName, true);
|
|
callback();
|
|
}
|
|
|
|
/**
|
|
* runOncePerModification
|
|
*
|
|
* Helper function similar to runOnce. The difference is that runOnce runs the
|
|
* callback once when the policy is set, then never again.
|
|
* runOncePerModification runs the callback once each time the policy value
|
|
* changes from its previous value.
|
|
* If the callback that was passed is an async function, you can await on this
|
|
* function to await for the callback.
|
|
*
|
|
* @param {string} actionName
|
|
* A given name which will be used to track if this callback has run.
|
|
* This string will be part of a pref name.
|
|
* @param {string} policyValue
|
|
* The current value of the policy. This will be compared to previous
|
|
* values given to this function to determine if the policy value has
|
|
* changed. Regardless of the data type of the policy, this must be a
|
|
* string.
|
|
* @param {Function} callback
|
|
* The callback to be run when the pref value changes
|
|
* @returns Promise
|
|
* A promise that will resolve once the callback finishes running.
|
|
*
|
|
*/
|
|
async function runOncePerModification(actionName, policyValue, callback) {
|
|
let prefName = `browser.policies.runOncePerModification.${actionName}`;
|
|
let oldPolicyValue = Services.prefs.getStringPref(prefName, undefined);
|
|
if (policyValue === oldPolicyValue) {
|
|
log.debug(`Not running action ${actionName} again because the policy's value is unchanged`);
|
|
return Promise.resolve();
|
|
}
|
|
Services.prefs.setStringPref(prefName, policyValue);
|
|
return callback();
|
|
}
|
|
|
|
let gChromeURLSBlocked = false;
|
|
|
|
// If any about page is blocked, we block the loading of all
|
|
// chrome:// URLs in the browser window.
|
|
function blockAboutPage(manager, feature, neededOnContentProcess = false) {
|
|
manager.disallowFeature(feature, neededOnContentProcess);
|
|
if (!gChromeURLSBlocked) {
|
|
blockAllChromeURLs();
|
|
gChromeURLSBlocked = true;
|
|
}
|
|
}
|
|
|
|
let ChromeURLBlockPolicy = {
|
|
shouldLoad(contentLocation, loadInfo, mimeTypeGuess) {
|
|
let contentType = loadInfo.externalContentPolicyType;
|
|
if (contentLocation.scheme == "chrome" &&
|
|
contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT &&
|
|
loadInfo.loadingContext &&
|
|
loadInfo.loadingContext.baseURI == AppConstants.BROWSER_CHROME_URL &&
|
|
contentLocation.host != "mochitests" &&
|
|
contentLocation.host != "devtools") {
|
|
return Ci.nsIContentPolicy.REJECT_REQUEST;
|
|
}
|
|
return Ci.nsIContentPolicy.ACCEPT;
|
|
},
|
|
shouldProcess(contentLocation, loadInfo, mimeTypeGuess) {
|
|
return Ci.nsIContentPolicy.ACCEPT;
|
|
},
|
|
classDescription: "Policy Engine Content Policy",
|
|
contractID: "@mozilla-org/policy-engine-content-policy-service;1",
|
|
classID: Components.ID("{ba7b9118-cabc-4845-8b26-4215d2a59ed7}"),
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPolicy]),
|
|
createInstance(outer, iid) {
|
|
return this.QueryInterface(iid);
|
|
},
|
|
};
|
|
|
|
|
|
function blockAllChromeURLs() {
|
|
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
|
registrar.registerFactory(ChromeURLBlockPolicy.classID,
|
|
ChromeURLBlockPolicy.classDescription,
|
|
ChromeURLBlockPolicy.contractID,
|
|
ChromeURLBlockPolicy);
|
|
|
|
Services.catMan.addCategoryEntry("content-policy",
|
|
ChromeURLBlockPolicy.contractID,
|
|
ChromeURLBlockPolicy.contractID, false, true);
|
|
}
|
|
|
|
function pemToBase64(pem) {
|
|
return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
|
|
.replace(/-----END CERTIFICATE-----/, "")
|
|
.replace(/[\r\n]/g, "");
|
|
}
|