Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
3
* You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
"use strict";
6
7
const { XPCOMUtils } = ChromeUtils.import(
9
);
10
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
11
const { AppConstants } = ChromeUtils.import(
13
);
14
15
XPCOMUtils.defineLazyServiceGetters(this, {
16
gCertDB: ["@mozilla.org/security/x509certdb;1", "nsIX509CertDB"],
17
gXulStore: ["@mozilla.org/xul/xulstore;1", "nsIXULStore"],
18
});
19
20
XPCOMUtils.defineLazyModuleGetters(this, {
27
});
28
29
XPCOMUtils.defineLazyGlobalGetters(this, ["File", "FileReader"]);
30
31
const PREF_LOGLEVEL = "browser.policies.loglevel";
32
const BROWSER_DOCUMENT_URL = AppConstants.BROWSER_CHROME_URL;
33
34
XPCOMUtils.defineLazyGetter(this, "log", () => {
35
let { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm");
36
return new ConsoleAPI({
37
prefix: "Policies.jsm",
38
// tip: set maxLogLevel to "debug" and use log.debug() to create detailed
39
// messages during development. See LOG_LEVELS in Console.jsm for details.
40
maxLogLevel: "error",
41
maxLogLevelPref: PREF_LOGLEVEL,
42
});
43
});
44
45
var EXPORTED_SYMBOLS = ["Policies"];
46
47
/*
48
* ============================
49
* = POLICIES IMPLEMENTATIONS =
50
* ============================
51
*
52
* The Policies object below is where the implementation for each policy
53
* happens. An object for each policy should be defined, containing
54
* callback functions that will be called by the engine.
55
*
56
* See the _callbacks object in EnterprisePolicies.js for the list of
57
* possible callbacks and an explanation of each.
58
*
59
* Each callback will be called with two parameters:
60
* - manager
61
* This is the EnterprisePoliciesManager singleton object from
62
* EnterprisePolicies.js
63
*
64
* - param
65
* The parameter defined for this policy in policies-schema.json.
66
* It will be different for each policy. It could be a boolean,
67
* a string, an array or a complex object. All parameters have
68
* been validated according to the schema, and no unknown
69
* properties will be present on them.
70
*
71
* The callbacks will be bound to their parent policy object.
72
*/
73
var Policies = {
74
"3rdparty": {
75
onBeforeAddons(manager, param) {
76
manager.setExtensionPolicies(param.Extensions);
77
},
78
},
79
80
AppUpdateURL: {
81
onBeforeAddons(manager, param) {
82
setDefaultPref("app.update.url", param.href);
83
},
84
},
85
86
Authentication: {
87
onBeforeAddons(manager, param) {
88
let locked = true;
89
if ("Locked" in param) {
90
locked = param.Locked;
91
}
92
93
if ("SPNEGO" in param) {
94
setDefaultPref(
95
"network.negotiate-auth.trusted-uris",
96
param.SPNEGO.join(", "),
97
locked
98
);
99
}
100
if ("Delegated" in param) {
101
setDefaultPref(
102
"network.negotiate-auth.delegation-uris",
103
param.Delegated.join(", "),
104
locked
105
);
106
}
107
if ("NTLM" in param) {
108
setDefaultPref(
109
"network.automatic-ntlm-auth.trusted-uris",
110
param.NTLM.join(", "),
111
locked
112
);
113
}
114
if ("AllowNonFQDN" in param) {
115
if ("NTLM" in param.AllowNonFQDN) {
116
setDefaultPref(
117
"network.automatic-ntlm-auth.allow-non-fqdn",
118
param.AllowNonFQDN.NTLM,
119
locked
120
);
121
}
122
if ("SPNEGO" in param.AllowNonFQDN) {
123
setDefaultPref(
124
"network.negotiate-auth.allow-non-fqdn",
125
param.AllowNonFQDN.SPNEGO,
126
locked
127
);
128
}
129
}
130
if ("AllowProxies" in param) {
131
if ("NTLM" in param.AllowProxies) {
132
setDefaultPref(
133
"network.automatic-ntlm-auth.allow-proxies",
134
param.AllowProxies.NTLM,
135
locked
136
);
137
}
138
if ("SPNEGO" in param.AllowProxies) {
139
setDefaultPref(
140
"network.negotiate-auth.allow-proxies",
141
param.AllowProxies.SPNEGO,
142
locked
143
);
144
}
145
}
146
},
147
},
148
149
BlockAboutAddons: {
150
onBeforeUIStartup(manager, param) {
151
if (param) {
152
blockAboutPage(manager, "about:addons", true);
153
}
154
},
155
},
156
157
BlockAboutConfig: {
158
onBeforeUIStartup(manager, param) {
159
if (param) {
160
blockAboutPage(manager, "about:config");
161
setAndLockPref("devtools.chrome.enabled", false);
162
}
163
},
164
},
165
166
BlockAboutProfiles: {
167
onBeforeUIStartup(manager, param) {
168
if (param) {
169
blockAboutPage(manager, "about:profiles");
170
}
171
},
172
},
173
174
BlockAboutSupport: {
175
onBeforeUIStartup(manager, param) {
176
if (param) {
177
blockAboutPage(manager, "about:support");
178
}
179
},
180
},
181
182
Bookmarks: {
183
onAllWindowsRestored(manager, param) {
184
BookmarksPolicies.processBookmarks(param);
185
},
186
},
187
188
CaptivePortal: {
189
onBeforeAddons(manager, param) {
190
setAndLockPref("network.captive-portal-service.enabled", param);
191
},
192
},
193
194
Certificates: {
195
onBeforeAddons(manager, param) {
196
if ("ImportEnterpriseRoots" in param) {
197
setAndLockPref(
198
"security.enterprise_roots.enabled",
199
param.ImportEnterpriseRoots
200
);
201
}
202
if ("Install" in param) {
203
(async () => {
204
let dirs = [];
205
let platform = AppConstants.platform;
206
if (platform == "win") {
207
dirs = [
208
// Ugly, but there is no official way to get %USERNAME\AppData\Roaming\Mozilla.
209
Services.dirsvc.get("XREUSysExt", Ci.nsIFile).parent,
210
// Even more ugly, but there is no official way to get %USERNAME\AppData\Local\Mozilla.
211
Services.dirsvc.get("DefProfLRt", Ci.nsIFile).parent.parent,
212
];
213
} else if (platform == "macosx" || platform == "linux") {
214
dirs = [
215
// These two keys are named wrong. They return the Mozilla directory.
216
Services.dirsvc.get("XREUserNativeManifests", Ci.nsIFile),
217
Services.dirsvc.get("XRESysNativeManifests", Ci.nsIFile),
218
];
219
}
220
dirs.unshift(Services.dirsvc.get("XREAppDist", Ci.nsIFile));
221
for (let certfilename of param.Install) {
222
let certfile;
223
try {
224
certfile = Cc["@mozilla.org/file/local;1"].createInstance(
225
Ci.nsIFile
226
);
227
certfile.initWithPath(certfilename);
228
} catch (e) {
229
for (let dir of dirs) {
230
certfile = dir.clone();
231
certfile.append(
232
platform == "linux" ? "certificates" : "Certificates"
233
);
234
certfile.append(certfilename);
235
if (certfile.exists()) {
236
break;
237
}
238
}
239
}
240
let file;
241
try {
242
file = await File.createFromNsIFile(certfile);
243
} catch (e) {
244
log.error(`Unable to find certificate - ${certfilename}`);
245
continue;
246
}
247
let reader = new FileReader();
248
reader.onloadend = function() {
249
if (reader.readyState != reader.DONE) {
250
log.error(`Unable to read certificate - ${certfile.path}`);
251
return;
252
}
253
let certFile = reader.result;
254
let certFileArray = [];
255
for (let i = 0; i < certFile.length; i++) {
256
certFileArray.push(certFile.charCodeAt(i));
257
}
258
let cert;
259
try {
260
cert = gCertDB.constructX509(certFileArray);
261
} catch (e) {
262
try {
263
// It might be PEM instead of DER.
264
cert = gCertDB.constructX509FromBase64(pemToBase64(certFile));
265
} catch (ex) {
266
log.error(`Unable to add certificate - ${certfile.path}`);
267
}
268
}
269
if (cert) {
270
if (
271
gCertDB.isCertTrusted(
272
cert,
273
Ci.nsIX509Cert.CA_CERT,
274
Ci.nsIX509CertDB.TRUSTED_SSL
275
)
276
) {
277
// Certificate is already installed.
278
return;
279
}
280
try {
281
gCertDB.addCert(certFile, "CT,CT,");
282
} catch (e) {
283
// It might be PEM instead of DER.
284
gCertDB.addCertFromBase64(pemToBase64(certFile), "CT,CT,");
285
}
286
}
287
};
288
reader.readAsBinaryString(file);
289
}
290
})();
291
}
292
},
293
},
294
295
Cookies: {
296
onBeforeUIStartup(manager, param) {
297
addAllowDenyPermissions("cookie", param.Allow, param.Block);
298
299
if (param.Block) {
300
const hosts = param.Block.map(url => url.hostname)
301
.sort()
302
.join("\n");
303
runOncePerModification("clearCookiesForBlockedHosts", hosts, () => {
304
for (let blocked of param.Block) {
305
Services.cookies.removeCookiesWithOriginAttributes(
306
"{}",
307
blocked.hostname
308
);
309
}
310
});
311
}
312
313
if (
314
param.Default !== undefined ||
315
param.AcceptThirdParty !== undefined ||
316
param.RejectTracker !== undefined ||
317
param.Locked
318
) {
319
const ACCEPT_COOKIES = 0;
320
const REJECT_THIRD_PARTY_COOKIES = 1;
321
const REJECT_ALL_COOKIES = 2;
322
const REJECT_UNVISITED_THIRD_PARTY = 3;
323
const REJECT_TRACKER = 4;
324
325
let newCookieBehavior = ACCEPT_COOKIES;
326
if (param.Default !== undefined && !param.Default) {
327
newCookieBehavior = REJECT_ALL_COOKIES;
328
} else if (param.AcceptThirdParty) {
329
if (param.AcceptThirdParty == "never") {
330
newCookieBehavior = REJECT_THIRD_PARTY_COOKIES;
331
} else if (param.AcceptThirdParty == "from-visited") {
332
newCookieBehavior = REJECT_UNVISITED_THIRD_PARTY;
333
}
334
} else if (param.RejectTracker !== undefined && param.RejectTracker) {
335
newCookieBehavior = REJECT_TRACKER;
336
}
337
338
setDefaultPref(
339
"network.cookie.cookieBehavior",
340
newCookieBehavior,
341
param.Locked
342
);
343
}
344
345
const KEEP_COOKIES_UNTIL_EXPIRATION = 0;
346
const KEEP_COOKIES_UNTIL_END_OF_SESSION = 2;
347
348
if (param.ExpireAtSessionEnd !== undefined || param.Locked) {
349
let newLifetimePolicy = KEEP_COOKIES_UNTIL_EXPIRATION;
350
if (param.ExpireAtSessionEnd) {
351
newLifetimePolicy = KEEP_COOKIES_UNTIL_END_OF_SESSION;
352
}
353
354
setDefaultPref(
355
"network.cookie.lifetimePolicy",
356
newLifetimePolicy,
357
param.Locked
358
);
359
}
360
},
361
},
362
363
DefaultDownloadDirectory: {
364
onBeforeAddons(manager, param) {
365
setDefaultPref("browser.download.dir", replacePathVariables(param));
366
// If a custom download directory is being used, just lock folder list to 2.
367
setAndLockPref("browser.download.folderList", 2);
368
},
369
},
370
371
DisableAppUpdate: {
372
onBeforeAddons(manager, param) {
373
if (param) {
374
manager.disallowFeature("appUpdate");
375
}
376
},
377
},
378
379
DisableBuiltinPDFViewer: {
380
onBeforeAddons(manager, param) {
381
if (param) {
382
setAndLockPref("pdfjs.disabled", true);
383
}
384
},
385
},
386
387
DisableDeveloperTools: {
388
onBeforeAddons(manager, param) {
389
if (param) {
390
setAndLockPref("devtools.policy.disabled", true);
391
setAndLockPref("devtools.chrome.enabled", false);
392
393
manager.disallowFeature("devtools");
394
blockAboutPage(manager, "about:devtools");
395
blockAboutPage(manager, "about:debugging");
396
blockAboutPage(manager, "about:devtools-toolbox");
397
blockAboutPage(manager, "about:profiling");
398
}
399
},
400
},
401
402
DisableFeedbackCommands: {
403
onBeforeUIStartup(manager, param) {
404
if (param) {
405
manager.disallowFeature("feedbackCommands");
406
}
407
},
408
},
409
410
DisableFirefoxAccounts: {
411
onBeforeAddons(manager, param) {
412
if (param) {
413
setAndLockPref("identity.fxaccounts.enabled", false);
414
setAndLockPref("trailhead.firstrun.branches", "nofirstrun");
415
}
416
},
417
},
418
419
DisableFirefoxScreenshots: {
420
onBeforeAddons(manager, param) {
421
if (param) {
422
setAndLockPref("extensions.screenshots.disabled", true);
423
}
424
},
425
},
426
427
DisableFirefoxStudies: {
428
onBeforeAddons(manager, param) {
429
if (param) {
430
manager.disallowFeature("Shield");
431
setAndLockPref(
432
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons",
433
false
434
);
435
setAndLockPref(
436
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features",
437
false
438
);
439
}
440
},
441
},
442
443
DisableForgetButton: {
444
onProfileAfterChange(manager, param) {
445
if (param) {
446
setAndLockPref("privacy.panicButton.enabled", false);
447
}
448
},
449
},
450
451
DisableFormHistory: {
452
onBeforeUIStartup(manager, param) {
453
if (param) {
454
setAndLockPref("browser.formfill.enable", false);
455
}
456
},
457
},
458
459
DisableMasterPasswordCreation: {
460
onBeforeUIStartup(manager, param) {
461
if (param) {
462
manager.disallowFeature("createMasterPassword");
463
}
464
},
465
},
466
467
DisablePasswordReveal: {
468
onBeforeUIStartup(manager, param) {
469
if (param) {
470
manager.disallowFeature("passwordReveal");
471
}
472
},
473
},
474
475
DisablePocket: {
476
onBeforeAddons(manager, param) {
477
if (param) {
478
setAndLockPref("extensions.pocket.enabled", false);
479
}
480
},
481
},
482
483
DisablePrivateBrowsing: {
484
onBeforeAddons(manager, param) {
485
if (param) {
486
manager.disallowFeature("privatebrowsing");
487
blockAboutPage(manager, "about:privatebrowsing", true);
488
setAndLockPref("browser.privatebrowsing.autostart", false);
489
}
490
},
491
},
492
493
DisableProfileImport: {
494
onBeforeUIStartup(manager, param) {
495
if (param) {
496
manager.disallowFeature("profileImport");
497
setAndLockPref(
498
"browser.newtabpage.activity-stream.migrationExpired",
499
true
500
);
501
}
502
},
503
},
504
505
DisableProfileRefresh: {
506
onBeforeUIStartup(manager, param) {
507
if (param) {
508
manager.disallowFeature("profileRefresh");
509
setAndLockPref("browser.disableResetPrompt", true);
510
}
511
},
512
},
513
514
DisableSafeMode: {
515
onBeforeUIStartup(manager, param) {
516
if (param) {
517
manager.disallowFeature("safeMode");
518
}
519
},
520
},
521
522
DisableSecurityBypass: {
523
onBeforeUIStartup(manager, param) {
524
if ("InvalidCertificate" in param) {
525
setAndLockPref(
526
"security.certerror.hideAddException",
527
param.InvalidCertificate
528
);
529
}
530
531
if ("SafeBrowsing" in param) {
532
setAndLockPref(
533
"browser.safebrowsing.allowOverride",
534
!param.SafeBrowsing
535
);
536
}
537
},
538
},
539
540
DisableSetDesktopBackground: {
541
onBeforeUIStartup(manager, param) {
542
if (param) {
543
manager.disallowFeature("setDesktopBackground");
544
}
545
},
546
},
547
548
DisableSystemAddonUpdate: {
549
onBeforeAddons(manager, param) {
550
if (param) {
551
manager.disallowFeature("SysAddonUpdate");
552
}
553
},
554
},
555
556
DisableTelemetry: {
557
onBeforeAddons(manager, param) {
558
if (param) {
559
setAndLockPref("datareporting.healthreport.uploadEnabled", false);
560
setAndLockPref("datareporting.policy.dataSubmissionEnabled", false);
561
blockAboutPage(manager, "about:telemetry");
562
}
563
},
564
},
565
566
DisplayBookmarksToolbar: {
567
onBeforeUIStartup(manager, param) {
568
let value = (!param).toString();
569
// This policy is meant to change the default behavior, not to force it.
570
// If this policy was alreay applied and the user chose to re-hide the
571
// bookmarks toolbar, do not show it again.
572
runOncePerModification("displayBookmarksToolbar", value, () => {
573
gXulStore.setValue(
574
BROWSER_DOCUMENT_URL,
575
"PersonalToolbar",
576
"collapsed",
577
value
578
);
579
});
580
},
581
},
582
583
DisplayMenuBar: {
584
onBeforeUIStartup(manager, param) {
585
let value;
586
if (
587
typeof param === "boolean" ||
588
param == "default-on" ||
589
param == "default-off"
590
) {
591
switch (param) {
592
case "default-on":
593
value = "false";
594
break;
595
case "default-off":
596
value = "true";
597
break;
598
default:
599
value = (!param).toString();
600
break;
601
}
602
// This policy is meant to change the default behavior, not to force it.
603
// If this policy was already applied and the user chose to re-hide the
604
// menu bar, do not show it again.
605
runOncePerModification("displayMenuBar", value, () => {
606
gXulStore.setValue(
607
BROWSER_DOCUMENT_URL,
608
"toolbar-menubar",
609
"autohide",
610
value
611
);
612
});
613
} else {
614
switch (param) {
615
case "always":
616
value = "false";
617
break;
618
case "never":
619
// Make sure Alt key doesn't show the menubar
620
setAndLockPref("ui.key.menuAccessKeyFocuses", false);
621
value = "true";
622
break;
623
}
624
gXulStore.setValue(
625
BROWSER_DOCUMENT_URL,
626
"toolbar-menubar",
627
"autohide",
628
value
629
);
630
manager.disallowFeature("hideShowMenuBar");
631
}
632
},
633
},
634
635
DNSOverHTTPS: {
636
onBeforeAddons(manager, param) {
637
if ("Enabled" in param) {
638
let mode = param.Enabled ? 2 : 5;
639
setDefaultPref("network.trr.mode", mode, param.Locked);
640
}
641
if (param.ProviderURL) {
642
setDefaultPref("network.trr.uri", param.ProviderURL.href, param.Locked);
643
}
644
},
645
},
646
647
DontCheckDefaultBrowser: {
648
onBeforeUIStartup(manager, param) {
649
setAndLockPref("browser.shell.checkDefaultBrowser", !param);
650
},
651
},
652
653
DownloadDirectory: {
654
onBeforeAddons(manager, param) {
655
setAndLockPref("browser.download.dir", replacePathVariables(param));
656
// If a custom download directory is being used, just lock folder list to 2.
657
setAndLockPref("browser.download.folderList", 2);
658
// Per Chrome spec, user can't choose to download every time
659
// if this is set.
660
setAndLockPref("browser.download.useDownloadDir", true);
661
},
662
},
663
664
EnableTrackingProtection: {
665
onBeforeUIStartup(manager, param) {
666
if (param.Value) {
667
setDefaultPref(
668
"privacy.trackingprotection.enabled",
669
true,
670
param.Locked
671
);
672
setDefaultPref(
673
"privacy.trackingprotection.pbmode.enabled",
674
true,
675
param.Locked
676
);
677
} else {
678
setAndLockPref("privacy.trackingprotection.enabled", false);
679
setAndLockPref("privacy.trackingprotection.pbmode.enabled", false);
680
}
681
if ("Cryptomining" in param) {
682
setDefaultPref(
683
"privacy.trackingprotection.cryptomining.enabled",
684
param.Cryptomining,
685
param.Locked
686
);
687
}
688
if ("Fingerprinting" in param) {
689
setDefaultPref(
690
"privacy.trackingprotection.fingerprinting.enabled",
691
param.Fingerprinting,
692
param.Locked
693
);
694
}
695
if ("Exceptions" in param) {
696
addAllowDenyPermissions("trackingprotection", param.Exceptions);
697
}
698
},
699
},
700
701
Extensions: {
702
onBeforeUIStartup(manager, param) {
703
let uninstallingPromise = Promise.resolve();
704
if ("Uninstall" in param) {
705
uninstallingPromise = runOncePerModification(
706
"extensionsUninstall",
707
JSON.stringify(param.Uninstall),
708
async () => {
709
// If we're uninstalling add-ons, re-run the extensionsInstall runOnce even if it hasn't
710
// changed, which will allow add-ons to be updated.
711
Services.prefs.clearUserPref(
712
"browser.policies.runOncePerModification.extensionsInstall"
713
);
714
let addons = await AddonManager.getAddonsByIDs(param.Uninstall);
715
for (let addon of addons) {
716
if (addon) {
717
try {
718
await addon.uninstall();
719
} catch (e) {
720
// This can fail for add-ons that can't be uninstalled.
721
log.debug(`Add-on ID (${addon.id}) couldn't be uninstalled.`);
722
}
723
}
724
}
725
}
726
);
727
}
728
if ("Install" in param) {
729
runOncePerModification(
730
"extensionsInstall",
731
JSON.stringify(param.Install),
732
async () => {
733
await uninstallingPromise;
734
for (let location of param.Install) {
735
let uri;
736
try {
737
// We need to try as a file first because
738
// Windows paths are valid URIs.
739
// This is done for legacy support (old API)
740
let xpiFile = new FileUtils.File(location);
741
uri = Services.io.newFileURI(xpiFile);
742
} catch (e) {
743
uri = Services.io.newURI(location);
744
}
745
installAddonFromURL(uri.spec);
746
}
747
}
748
);
749
}
750
if ("Locked" in param) {
751
for (let ID of param.Locked) {
752
manager.disallowFeature(`uninstall-extension:${ID}`);
753
manager.disallowFeature(`disable-extension:${ID}`);
754
}
755
}
756
},
757
},
758
759
ExtensionSettings: {
760
onBeforeAddons(manager, param) {
761
try {
762
manager.setExtensionSettings(param);
763
} catch (e) {
764
log.error("Invalid ExtensionSettings");
765
}
766
},
767
async onBeforeUIStartup(manager, param) {
768
let extensionSettings = param;
769
let blockAllExtensions = false;
770
if ("*" in extensionSettings) {
771
if (
772
"installation_mode" in extensionSettings["*"] &&
773
extensionSettings["*"].installation_mode == "blocked"
774
) {
775
blockAllExtensions = true;
776
// Turn off discovery pane in about:addons
777
setAndLockPref("extensions.getAddons.showPane", false);
778
// Turn off recommendations
779
setAndLockPref(
780
"extensions.htmlaboutaddons.recommendations.enable",
781
false
782
);
783
// Block about:debugging
784
blockAboutPage(manager, "about:debugging");
785
}
786
}
787
let addons = await AddonManager.getAllAddons();
788
let allowedExtensions = [];
789
for (let extensionID in extensionSettings) {
790
if (extensionID == "*") {
791
// Ignore global settings
792
continue;
793
}
794
if ("installation_mode" in extensionSettings[extensionID]) {
795
if (
796
extensionSettings[extensionID].installation_mode ==
797
"force_installed" ||
798
extensionSettings[extensionID].installation_mode ==
799
"normal_installed"
800
) {
801
if (!extensionSettings[extensionID].install_url) {
802
throw new Error(`Missing install_url for ${extensionID}`);
803
}
804
if (!addons.find(addon => addon.id == extensionID)) {
805
installAddonFromURL(
806
extensionSettings[extensionID].install_url,
807
extensionID
808
);
809
}
810
manager.disallowFeature(`uninstall-extension:${extensionID}`);
811
if (
812
extensionSettings[extensionID].installation_mode ==
813
"force_installed"
814
) {
815
manager.disallowFeature(`disable-extension:${extensionID}`);
816
}
817
allowedExtensions.push(extensionID);
818
} else if (
819
extensionSettings[extensionID].installation_mode == "allowed"
820
) {
821
allowedExtensions.push(extensionID);
822
} else if (
823
extensionSettings[extensionID].installation_mode == "blocked"
824
) {
825
if (addons.find(addon => addon.id == extensionID)) {
826
// Can't use the addon from getActiveAddons since it doesn't have uninstall.
827
let addon = await AddonManager.getAddonByID(extensionID);
828
try {
829
await addon.uninstall();
830
} catch (e) {
831
// This can fail for add-ons that can't be uninstalled.
832
log.debug(`Add-on ID (${addon.id}) couldn't be uninstalled.`);
833
}
834
}
835
}
836
}
837
}
838
if (blockAllExtensions) {
839
for (let addon of addons) {
840
if (
841
addon.isSystem ||
842
addon.isBuiltin ||
843
!(addon.scope & AddonManager.SCOPE_PROFILE)
844
) {
845
continue;
846
}
847
if (!allowedExtensions.includes(addon.id)) {
848
try {
849
// Can't use the addon from getActiveAddons since it doesn't have uninstall.
850
let addonToUninstall = await AddonManager.getAddonByID(addon.id);
851
await addonToUninstall.uninstall();
852
} catch (e) {
853
// This can fail for add-ons that can't be uninstalled.
854
log.debug(`Add-on ID (${addon.id}) couldn't be uninstalled.`);
855
}
856
}
857
}
858
}
859
},
860
},
861
862
ExtensionUpdate: {
863
onBeforeAddons(manager, param) {
864
if (!param) {
865
setAndLockPref("extensions.update.enabled", param);
866
}
867
},
868
},
869
870
FirefoxHome: {
871
onBeforeAddons(manager, param) {
872
let locked = param.Locked || false;
873
if ("Search" in param) {
874
setDefaultPref(
875
"browser.newtabpage.activity-stream.showSearch",
876
param.Search,
877
locked
878
);
879
}
880
if ("TopSites" in param) {
881
setDefaultPref(
882
"browser.newtabpage.activity-stream.feeds.topsites",
883
param.TopSites,
884
locked
885
);
886
}
887
if ("Highlights" in param) {
888
setDefaultPref(
889
"browser.newtabpage.activity-stream.feeds.section.highlights",
890
param.Highlights,
891
locked
892
);
893
}
894
if ("Pocket" in param) {
895
setDefaultPref(
896
"browser.newtabpage.activity-stream.feeds.section.topstories",
897
param.Pocket,
898
locked
899
);
900
}
901
if ("Snippets" in param) {
902
setDefaultPref(
903
"browser.newtabpage.activity-stream.feeds.snippets",
904
param.Snippets,
905
locked
906
);
907
}
908
},
909
},
910
911
FlashPlugin: {
912
onBeforeUIStartup(manager, param) {
913
addAllowDenyPermissions("plugin:flash", param.Allow, param.Block);
914
915
const FLASH_NEVER_ACTIVATE = 0;
916
const FLASH_ASK_TO_ACTIVATE = 1;
917
918
let flashPrefVal;
919
if (param.Default === undefined || param.Default) {
920
flashPrefVal = FLASH_ASK_TO_ACTIVATE;
921
} else {
922
flashPrefVal = FLASH_NEVER_ACTIVATE;
923
}
924
if (param.Locked) {
925
setAndLockPref("plugin.state.flash", flashPrefVal);
926
} else if (param.Default !== undefined) {
927
setDefaultPref("plugin.state.flash", flashPrefVal);
928
}
929
},
930
},
931
932
HardwareAcceleration: {
933
onBeforeAddons(manager, param) {
934
if (!param) {
935
setAndLockPref("layers.acceleration.disabled", true);
936
}
937
},
938
},
939
940
Homepage: {
941
onBeforeUIStartup(manager, param) {
942
// |homepages| will be a string containing a pipe-separated ('|') list of
943
// URLs because that is what the "Home page" section of about:preferences
944
// (and therefore what the pref |browser.startup.homepage|) accepts.
945
if (param.URL) {
946
let homepages = param.URL.href;
947
if (param.Additional && param.Additional.length) {
948
homepages += "|" + param.Additional.map(url => url.href).join("|");
949
}
950
setDefaultPref("browser.startup.homepage", homepages, param.Locked);
951
if (param.Locked) {
952
setAndLockPref(
953
"pref.browser.homepage.disable_button.current_page",
954
true
955
);
956
setAndLockPref(
957
"pref.browser.homepage.disable_button.bookmark_page",
958
true
959
);
960
setAndLockPref(
961
"pref.browser.homepage.disable_button.restore_default",
962
true
963
);
964
} else {
965
// Clear out old run once modification that is no longer used.
966
clearRunOnceModification("setHomepage");
967
}
968
}
969
if (param.StartPage) {
970
let prefValue;
971
switch (param.StartPage) {
972
case "none":
973
prefValue = 0;
974
break;
975
case "homepage":
976
prefValue = 1;
977
break;
978
case "previous-session":
979
prefValue = 3;
980
break;
981
}
982
setDefaultPref("browser.startup.page", prefValue, param.Locked);
983
}
984
},
985
},
986
987
InstallAddonsPermission: {
988
onBeforeUIStartup(manager, param) {
989
if ("Allow" in param) {
990
addAllowDenyPermissions("install", param.Allow, null);
991
}
992
if ("Default" in param) {
993
setAndLockPref("xpinstall.enabled", param.Default);
994
if (!param.Default) {
995
blockAboutPage(manager, "about:debugging");
996
setAndLockPref(
997
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons",
998
false
999
);
1000
setAndLockPref(
1001
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features",
1002
false
1003
);
1004
manager.disallowFeature("xpinstall");
1005
}
1006
}
1007
},
1008
},
1009
1010
LegacyProfiles: {
1011
// Handled in nsToolkitProfileService.cpp (Windows only)
1012
},
1013
1014
LocalFileLinks: {
1015
onBeforeAddons(manager, param) {
1016
// If there are existing capabilities, lock them with the policy pref.
1017
let policyNames = Services.prefs
1018
.getCharPref("capability.policy.policynames", "")
1019
.split(" ");
1020
policyNames.push("localfilelinks_policy");
1021
setAndLockPref("capability.policy.policynames", policyNames.join(" "));
1022
setAndLockPref(
1023
"capability.policy.localfilelinks_policy.checkloaduri.enabled",
1024
"allAccess"
1025
);
1026
setAndLockPref(
1027
"capability.policy.localfilelinks_policy.sites",
1028
param.join(" ")
1029
);
1030
},
1031
},
1032
1033
NetworkPrediction: {
1034
onBeforeAddons(manager, param) {
1035
setAndLockPref("network.dns.disablePrefetch", !param);
1036
setAndLockPref("network.dns.disablePrefetchFromHTTPS", !param);
1037
},
1038
},
1039
1040
NewTabPage: {
1041
onBeforeAddons(manager, param) {
1042
setAndLockPref("browser.newtabpage.enabled", param);
1043
},
1044
},
1045
1046
NoDefaultBookmarks: {
1047
onProfileAfterChange(manager, param) {
1048
if (param) {
1049
manager.disallowFeature("defaultBookmarks");
1050
}
1051
},
1052
},
1053
1054
OfferToSaveLogins: {
1055
onBeforeUIStartup(manager, param) {
1056
setAndLockPref("signon.rememberSignons", param);
1057
},
1058
},
1059
1060
OfferToSaveLoginsDefault: {
1061
onBeforeUIStartup(manager, param) {
1062
setDefaultPref("signon.rememberSignons", param);
1063
},
1064
},
1065
1066
OverrideFirstRunPage: {
1067
onProfileAfterChange(manager, param) {
1068
let url = param ? param.href : "";
1069
setAndLockPref("startup.homepage_welcome_url", url);
1070
setAndLockPref("trailhead.firstrun.branches", "nofirstrun");
1071
},
1072
},
1073
1074
OverridePostUpdatePage: {
1075
onProfileAfterChange(manager, param) {
1076
let url = param ? param.href : "";
1077
setAndLockPref("startup.homepage_override_url", url);
1078
// The pref startup.homepage_override_url is only used
1079
// as a fallback when the update.xml file hasn't provided
1080
// a specific post-update URL.
1081
manager.disallowFeature("postUpdateCustomPage");
1082
},
1083
},
1084
1085
PasswordManagerEnabled: {
1086
onBeforeUIStartup(manager, param) {
1087
if (!param) {
1088
blockAboutPage(manager, "about:logins", true);
1089
gBlockedChromePages.push("passwordManager.xhtml");
1090
setAndLockPref("pref.privacy.disable_button.view_passwords", true);
1091
}
1092
setAndLockPref("signon.rememberSignons", param);
1093
},
1094
},
1095
1096
Permissions: {
1097
onBeforeUIStartup(manager, param) {
1098
if (param.Camera) {
1099
addAllowDenyPermissions(
1100
"camera",
1101
param.Camera.Allow,
1102
param.Camera.Block
1103
);
1104
setDefaultPermission("camera", param.Camera);
1105
}
1106
1107
if (param.Microphone) {
1108
addAllowDenyPermissions(
1109
"microphone",
1110
param.Microphone.Allow,
1111
param.Microphone.Block
1112
);
1113
setDefaultPermission("microphone", param.Microphone);
1114
}
1115
1116
if (param.Location) {
1117
addAllowDenyPermissions(
1118
"geo",
1119
param.Location.Allow,
1120
param.Location.Block
1121
);
1122
setDefaultPermission("geo", param.Location);
1123
}
1124
1125
if (param.Notifications) {
1126
addAllowDenyPermissions(
1127
"desktop-notification",
1128
param.Notifications.Allow,
1129
param.Notifications.Block
1130
);
1131
setDefaultPermission("desktop-notification", param.Notifications);
1132
}
1133
},
1134
},
1135
1136
PopupBlocking: {
1137
onBeforeUIStartup(manager, param) {
1138
addAllowDenyPermissions("popup", param.Allow, null);
1139
1140
if (param.Locked) {
1141
let blockValue = true;
1142
if (param.Default !== undefined && !param.Default) {
1143
blockValue = false;
1144
}
1145
setAndLockPref("dom.disable_open_during_load", blockValue);
1146
} else if (param.Default !== undefined) {
1147
setDefaultPref("dom.disable_open_during_load", !!param.Default);
1148
}
1149
},
1150
},
1151
1152
Preferences: {
1153
onBeforeAddons(manager, param) {
1154
for (let preference in param) {
1155
setAndLockPref(preference, param[preference]);
1156
}
1157
},
1158
},
1159
1160
PromptForDownloadLocation: {
1161
onBeforeAddons(manager, param) {
1162
setAndLockPref("browser.download.useDownloadDir", !param);
1163
},
1164
},
1165
1166
Proxy: {
1167
onBeforeAddons(manager, param) {
1168
if (param.Locked) {
1169
manager.disallowFeature("changeProxySettings");
1170
ProxyPolicies.configureProxySettings(param, setAndLockPref);
1171
} else {
1172
ProxyPolicies.configureProxySettings(param, setDefaultPref);
1173
}
1174
},
1175
},
1176
1177
RequestedLocales: {
1178
onBeforeAddons(manager, param) {
1179
if (Array.isArray(param)) {
1180
Services.locale.requestedLocales = param;
1181
} else {
1182
Services.locale.requestedLocales = param.split(",");
1183
}
1184
},
1185
},
1186
1187
SanitizeOnShutdown: {
1188
onBeforeUIStartup(manager, param) {
1189
if (typeof param === "boolean") {
1190
setAndLockPref("privacy.sanitize.sanitizeOnShutdown", param);
1191
if (param) {
1192
setAndLockPref("privacy.clearOnShutdown.cache", true);
1193
setAndLockPref("privacy.clearOnShutdown.cookies", true);
1194
setAndLockPref("privacy.clearOnShutdown.downloads", true);
1195
setAndLockPref("privacy.clearOnShutdown.formdata", true);
1196
setAndLockPref("privacy.clearOnShutdown.history", true);
1197
setAndLockPref("privacy.clearOnShutdown.sessions", true);
1198
setAndLockPref("privacy.clearOnShutdown.siteSettings", true);
1199
setAndLockPref("privacy.clearOnShutdown.offlineApps", true);
1200
}
1201
} else {
1202
setAndLockPref("privacy.sanitize.sanitizeOnShutdown", true);
1203
if ("Cache" in param) {
1204
setAndLockPref("privacy.clearOnShutdown.cache", param.Cache);
1205
} else {
1206
setAndLockPref("privacy.clearOnShutdown.cache", false);
1207
}
1208
if ("Cookies" in param) {
1209
setAndLockPref("privacy.clearOnShutdown.cookies", param.Cookies);
1210
} else {
1211
setAndLockPref("privacy.clearOnShutdown.cookies", false);
1212
}
1213
if ("Downloads" in param) {
1214
setAndLockPref("privacy.clearOnShutdown.downloads", param.Downloads);
1215
} else {
1216
setAndLockPref("privacy.clearOnShutdown.downloads", false);
1217
}
1218
if ("FormData" in param) {
1219
setAndLockPref("privacy.clearOnShutdown.formdata", param.FormData);
1220
} else {
1221
setAndLockPref("privacy.clearOnShutdown.formdata", false);
1222
}
1223
if ("History" in param) {
1224
setAndLockPref("privacy.clearOnShutdown.history", param.History);
1225
} else {
1226
setAndLockPref("privacy.clearOnShutdown.history", false);
1227
}
1228
if ("Sessions" in param) {
1229
setAndLockPref("privacy.clearOnShutdown.sessions", param.Sessions);
1230
} else {
1231
setAndLockPref("privacy.clearOnShutdown.sessions", false);
1232
}
1233
if ("SiteSettings" in param) {
1234
setAndLockPref(
1235
"privacy.clearOnShutdown.siteSettings",
1236
param.SiteSettings
1237
);
1238
}
1239
if ("OfflineApps" in param) {
1240
setAndLockPref(
1241
"privacy.clearOnShutdown.offlineApps",
1242
param.OfflineApps
1243
);
1244
}
1245
}
1246
},
1247
},
1248
1249
SearchBar: {
1250
onAllWindowsRestored(manager, param) {
1251
// This policy is meant to change the default behavior, not to force it.
1252
// If this policy was already applied and the user chose move the search
1253
// bar, don't move it again.
1254
runOncePerModification("searchInNavBar", param, () => {
1255
if (param == "separate") {
1256
CustomizableUI.addWidgetToArea(
1257
"search-container",
1258
CustomizableUI.AREA_NAVBAR,
1259
CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1
1260
);
1261
} else if (param == "unified") {
1262
CustomizableUI.removeWidgetFromArea("search-container");
1263
}
1264
});
1265
},
1266
},
1267
1268
SearchEngines: {
1269
onBeforeUIStartup(manager, param) {
1270
if (param.PreventInstalls) {
1271
manager.disallowFeature("installSearchEngine", true);
1272
}
1273
},
1274
onAllWindowsRestored(manager, param) {
1275
Services.search.init().then(async () => {
1276
if (param.Remove) {
1277
// Only rerun if the list of engine names has changed.
1278
await runOncePerModification(
1279
"removeSearchEngines",
1280
JSON.stringify(param.Remove),
1281
async function() {
1282
for (let engineName of param.Remove) {
1283
let engine = Services.search.getEngineByName(engineName);
1284
if (engine) {
1285
try {
1286
await Services.search.removeEngine(engine);
1287
} catch (ex) {
1288
log.error("Unable to remove the search engine", ex);
1289
}
1290
}
1291
}
1292
}
1293
);
1294
}
1295
if (param.Add) {
1296
// Only rerun if the list of engine names has changed.
1297
let engineNameList = param.Add.map(engine => engine.Name);
1298
await runOncePerModification(
1299
"addSearchEngines",
1300
JSON.stringify(engineNameList),
1301
async function() {
1302
for (let newEngine of param.Add) {
1303
let newEngineParameters = {
1304
template: newEngine.URLTemplate,
1305
iconURL: newEngine.IconURL ? newEngine.IconURL.href : null,
1306
alias: newEngine.Alias,
1307
description: newEngine.Description,
1308
method: newEngine.Method,
1309
postData: newEngine.PostData,
1310
suggestURL: newEngine.SuggestURLTemplate,
1311
extensionID: "set-via-policy",
1312
queryCharset: "UTF-8",
1313
};
1314
try {
1315
await Services.search.addEngineWithDetails(
1316
newEngine.Name,
1317
newEngineParameters
1318
);
1319
} catch (ex) {
1320
log.error("Unable to add search engine", ex);
1321
}
1322
}
1323
}
1324
);
1325
}
1326
if (param.Default) {
1327
await runOncePerModification(
1328
"setDefaultSearchEngine",
1329
param.Default,
1330
async () => {
1331
let defaultEngine;
1332
try {
1333
defaultEngine = Services.search.getEngineByName(param.Default);
1334
if (!defaultEngine) {
1335
throw new Error("No engine by that name could be found");
1336
}
1337
} catch (ex) {
1338
log.error(
1339
`Search engine lookup failed when attempting to set ` +
1340
`the default engine. Requested engine was ` +
1341
`"${param.Default}".`,
1342
ex
1343
);
1344
}
1345
if (defaultEngine) {
1346
try {
1347
await Services.search.setDefault(defaultEngine);
1348
} catch (ex) {
1349
log.error("Unable to set the default search engine", ex);
1350
}
1351
}
1352
}
1353
);
1354
}
1355
if (param.DefaultPrivate) {
1356
await runOncePerModification(
1357
"setDefaultPrivateSearchEngine",
1358
param.DefaultPrivate,
1359
async () => {
1360
let defaultPrivateEngine;
1361
try {
1362
defaultPrivateEngine = Services.search.getEngineByName(
1363
param.DefaultPrivate
1364
);
1365
if (!defaultPrivateEngine) {
1366
throw new Error("No engine by that name could be found");
1367
}
1368
} catch (ex) {
1369
log.error(
1370
`Search engine lookup failed when attempting to set ` +
1371
`the default private engine. Requested engine was ` +
1372
`"${param.DefaultPrivate}".`,
1373
ex
1374
);
1375
}
1376
if (defaultPrivateEngine) {
1377
try {
1378
await Services.search.setDefaultPrivate(defaultPrivateEngine);
1379
} catch (ex) {
1380
log.error(
1381
"Unable to set the default private search engine",
1382
ex
1383
);
1384
}
1385
}
1386
}
1387
);
1388
}
1389
});
1390
},
1391
},
1392
1393
SearchSuggestEnabled: {
1394
onBeforeAddons(manager, param) {
1395
setAndLockPref("browser.urlbar.suggest.searches", param);
1396
setAndLockPref("browser.search.suggest.enabled", param);
1397
},
1398
},
1399
1400
SecurityDevices: {
1401
onProfileAfterChange(manager, param) {
1402
let securityDevices = param;
1403
let pkcs11db = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(
1404
Ci.nsIPKCS11ModuleDB
1405
);
1406
let moduleList = pkcs11db.listModules();
1407
for (let deviceName in securityDevices) {
1408
let foundModule = false;
1409
for (let module of moduleList) {
1410
if (module && module.libName === securityDevices[deviceName]) {
1411
foundModule = true;
1412
break;
1413
}
1414
}
1415
if (foundModule) {
1416
continue;
1417
}
1418
try {
1419
pkcs11db.addModule(deviceName, securityDevices[deviceName], 0, 0);
1420
} catch (ex) {
1421
log.error(`Unable to add security device ${deviceName}`);
1422
log.debug(ex);
1423
}
1424
}
1425
},
1426
},
1427
1428
SSLVersionMax: {
1429
onBeforeAddons(manager, param) {
1430
let tlsVersion;
1431
switch (param) {
1432
case "tls1":
1433
tlsVersion = 1;
1434
break;
1435
case "tls1.1":
1436
tlsVersion = 2;
1437
break;
1438
case "tls1.2":
1439
tlsVersion = 3;
1440
break;
1441
case "tls1.3":
1442
tlsVersion = 4;
1443
break;
1444
}
1445
setAndLockPref("security.tls.version.max", tlsVersion);
1446
},
1447
},
1448
1449
SSLVersionMin: {
1450
onBeforeAddons(manager, param) {
1451
let tlsVersion;
1452
switch (param) {
1453
case "tls1":
1454
tlsVersion = 1;
1455
break;
1456
case "tls1.1":
1457
tlsVersion = 2;
1458
break;
1459
case "tls1.2":
1460
tlsVersion = 3;
1461
break;
1462
case "tls1.3":
1463
tlsVersion = 4;
1464
break;
1465
}
1466
setAndLockPref("security.tls.version.min", tlsVersion);
1467
},
1468
},
1469
1470
SupportMenu: {
1471
onProfileAfterChange(manager, param) {
1472
manager.setSupportMenu(param);
1473
},
1474
},
1475
1476
WebsiteFilter: {
1477
onBeforeUIStartup(manager, param) {
1478
this.filter = new WebsiteFilter(
1479
param.Block || [],
1480
param.Exceptions || []
1481
);
1482
},
1483
},
1484
};
1485
1486
/*
1487
* ====================
1488
* = HELPER FUNCTIONS =
1489
* ====================
1490
*
1491
* The functions below are helpers to be used by several policies.
1492
*/
1493
1494
/**
1495
* setAndLockPref
1496
*
1497
* Sets the _default_ value of a pref, and locks it (meaning that
1498
* the default value will always be returned, independent from what
1499
* is stored as the user value).
1500
* The value is only changed in memory, and not stored to disk.
1501
*
1502
* @param {string} prefName
1503
* The pref to be changed
1504
* @param {boolean,number,string} prefValue
1505
* The value to set and lock
1506
*/
1507
function setAndLockPref(prefName, prefValue) {
1508
setDefaultPref(prefName, prefValue, true);
1509
}
1510
1511
/**
1512
* setDefaultPref
1513
*
1514
* Sets the _default_ value of a pref and optionally locks it.
1515
* The value is only changed in memory, and not stored to disk.
1516
*
1517
* @param {string} prefName
1518
* The pref to be changed
1519
* @param {boolean,number,string} prefValue
1520
* The value to set
1521
* @param {boolean} locked
1522
* Optionally lock the pref
1523
*/
1524
function setDefaultPref(prefName, prefValue, locked = false) {
1525
if (Services.prefs.prefIsLocked(prefName)) {
1526
Services.prefs.unlockPref(prefName);
1527
}
1528
1529
let defaults = Services.prefs.getDefaultBranch("");
1530
1531
switch (typeof prefValue) {
1532
case "boolean":
1533
defaults.setBoolPref(prefName, prefValue);
1534
break;
1535
1536
case "number":
1537
if (!Number.isInteger(prefValue)) {
1538
throw new Error(`Non-integer value for ${prefName}`);
1539
}
1540
1541
defaults.setIntPref(prefName, prefValue);
1542
break;
1543
1544
case "string":
1545
defaults.setStringPref(prefName, prefValue);
1546
break;
1547
}
1548
1549
if (locked) {
1550
Services.prefs.lockPref(prefName);
1551
}
1552
}
1553
1554
/**
1555
* setDefaultPermission
1556
*
1557
* Helper function to set preferences appropriately for the policy
1558
*
1559
* @param {string} policyName
1560
* The name of the policy to set
1561
* @param {object} policyParam
1562
* The object containing param for the policy
1563
*/
1564
function setDefaultPermission(policyName, policyParam) {
1565
if ("BlockNewRequests" in policyParam) {
1566
let prefName = "permissions.default." + policyName;
1567
1568
if (policyParam.BlockNewRequests) {
1569
setDefaultPref(prefName, 2, policyParam.Locked);
1570
} else {
1571
setDefaultPref(prefName, 0, policyParam.Locked);
1572
}
1573
}
1574
}
1575
1576
/**
1577
* addAllowDenyPermissions
1578
*
1579
* Helper function to call the permissions manager (Services.perms.addFromPrincipal)
1580
* for two arrays of URLs.
1581
*
1582
* @param {string} permissionName
1583
* The name of the permission to change
1584
* @param {array} allowList
1585
* The list of URLs to be set as ALLOW_ACTION for the chosen permission.
1586
* @param {array} blockList
1587
* The list of URLs to be set as DENY_ACTION for the chosen permission.
1588
*/
1589
function addAllowDenyPermissions(permissionName, allowList, blockList) {
1590
allowList = allowList || [];
1591
blockList = blockList || [];
1592
1593
for (let origin of allowList) {
1594
try {
1595
Services.perms.addFromPrincipal(
1596
Services.scriptSecurityManager.createContentPrincipalFromOrigin(origin),
1597
permissionName,
1598
Ci.nsIPermissionManager.ALLOW_ACTION,
1599
Ci.nsIPermissionManager.EXPIRE_POLICY
1600
);
1601
} catch (ex) {
1602
log.error(`Added by default for ${permissionName} permission in the permission
1603
manager - ${origin.href}`);
1604
}
1605
}
1606
1607
for (let origin of blockList) {
1608
Services.perms.addFromPrincipal(
1609
Services.scriptSecurityManager.createContentPrincipalFromOrigin(origin),
1610
permissionName,
1611
Ci.nsIPermissionManager.DENY_ACTION,
1612
Ci.nsIPermissionManager.EXPIRE_POLICY
1613
);
1614
}
1615
}
1616
1617
/**
1618
* runOnce
1619
*
1620
* Helper function to run a callback only once per policy.
1621
*
1622
* @param {string} actionName
1623
* A given name which will be used to track if this callback has run.
1624
* @param {Functon} callback
1625
* The callback to run only once.
1626
*/
1627
// eslint-disable-next-line no-unused-vars
1628
function runOnce(actionName, callback) {
1629
let prefName = `browser.policies.runonce.${actionName}`;
1630
if (Services.prefs.getBoolPref(prefName, false)) {
1631
log.debug(
1632
`Not running action ${actionName} again because it has already run.`
1633
);
1634
return;
1635
}
1636
Services.prefs.setBoolPref(prefName, true);
1637
callback();
1638
}
1639
1640
/**
1641
* runOncePerModification
1642
*
1643
* Helper function similar to runOnce. The difference is that runOnce runs the
1644
* callback once when the policy is set, then never again.
1645
* runOncePerModification runs the callback once each time the policy value
1646
* changes from its previous value.
1647
* If the callback that was passed is an async function, you can await on this
1648
* function to await for the callback.
1649
*
1650
* @param {string} actionName
1651
* A given name which will be used to track if this callback has run.
1652
* This string will be part of a pref name.
1653
* @param {string} policyValue
1654
* The current value of the policy. This will be compared to previous
1655
* values given to this function to determine if the policy value has
1656
* changed. Regardless of the data type of the policy, this must be a
1657
* string.
1658
* @param {Function} callback
1659
* The callback to be run when the pref value changes
1660
* @returns Promise
1661
* A promise that will resolve once the callback finishes running.
1662
*
1663
*/
1664
async function runOncePerModification(actionName, policyValue, callback) {
1665
let prefName = `browser.policies.runOncePerModification.${actionName}`;
1666
let oldPolicyValue = Services.prefs.getStringPref(prefName, undefined);
1667
if (policyValue === oldPolicyValue) {
1668
log.debug(
1669
`Not running action ${actionName} again because the policy's value is unchanged`
1670
);
1671
return Promise.resolve();
1672
}
1673
Services.prefs.setStringPref(prefName, policyValue);
1674
return callback();
1675
}
1676
1677
/**
1678
* clearRunOnceModification
1679
*
1680
* Helper function that clears a runOnce policy.
1681
*/
1682
function clearRunOnceModification(actionName) {
1683
let prefName = `browser.policies.runOncePerModification.${actionName}`;
1684
Services.prefs.clearUserPref(prefName);
1685
}
1686
1687
function replacePathVariables(path) {
1688
if (path.includes("${home}")) {
1689
return path.replace("${home}", FileUtils.getFile("Home", []).path);
1690
}
1691
return path;
1692
}
1693
1694
/**
1695
* installAddonFromURL
1696
*
1697
* Helper function that installs an addon from a URL
1698
* and verifies that the addon ID matches.
1699
*/
1700
function installAddonFromURL(url, extensionID) {
1701
AddonManager.getInstallForURL(url, {
1702
telemetryInfo: { source: "enterprise-policy" },
1703
}).then(install => {
1704
if (install.addon && install.addon.appDisabled) {
1705
log.error(`Incompatible add-on - ${location}`);
1706
install.cancel();
1707
return;
1708
}
1709
let listener = {
1710
/* eslint-disable-next-line no-shadow */
1711
onDownloadEnded: install => {
1712
if (extensionID && install.addon.id != extensionID) {
1713
log.error(
1714
`Add-on downloaded from ${url} had unexpected id (got ${
1715
install.addon.id
1716
} expected ${extensionID})`
1717
);
1718
install.removeListener(listener);
1719
install.cancel();
1720
}
1721
if (install.addon && install.addon.appDisabled) {
1722
log.error(`Incompatible add-on - ${url}`);
1723
install.removeListener(listener);
1724
install.cancel();
1725
}
1726
},
1727
onDownloadFailed: () => {
1728
install.removeListener(listener);
1729
log.error(
1730
`Download failed - ${AddonManager.errorToString(
1731
install.error
1732
)} - ${url}`
1733
);
1734
clearRunOnceModification("extensionsInstall");
1735
},
1736
onInstallFailed: () => {
1737
install.removeListener(listener);
1738
log.error(
1739
`Installation failed - ${AddonManager.errorToString(
1740
install.error
1741
)} - {url}`
1742
);
1743
},
1744
onInstallEnded: () => {
1745
install.removeListener(listener);
1746
log.debug(`Installation succeeded - ${url}`);
1747
},
1748
};
1749
install.addListener(listener);
1750
install.install();
1751
});
1752
}
1753
1754
let gBlockedChromePages = [];
1755
1756
function blockAboutPage(manager, feature, neededOnContentProcess = false) {
1757
if (!gBlockedChromePages.length) {
1758
addChromeURLBlocker();
1759
}
1760
manager.disallowFeature(feature, neededOnContentProcess);
1761
let splitURL = Services.io
1762
.newChannelFromURI(
1763
Services.io.newURI(feature),
1764
null,
1765
Services.scriptSecurityManager.getSystemPrincipal(),
1766
null,
1767
0,
1768
Ci.nsIContentPolicy.TYPE_OTHER
1769
)
1770
.URI.spec.split("/");
1771
// about:debugging uses index.html for a filename, so we need to rely
1772
// on more than just the filename.
1773
let fileName =
1774
splitURL[splitURL.length - 2] + "/" + splitURL[splitURL.length - 1];
1775
gBlockedChromePages.push(fileName);
1776
if (feature == "about:config") {
1777
// Hide old page until it is removed
1778
gBlockedChromePages.push("config.xhtml");
1779
}
1780
}
1781
1782
let ChromeURLBlockPolicy = {
1783
shouldLoad(contentLocation, loadInfo, mimeTypeGuess) {
1784
let contentType = loadInfo.externalContentPolicyType;
1785
if (
1786
contentLocation.scheme == "chrome" &&
1787
contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT &&
1788
loadInfo.loadingContext &&
1789
loadInfo.loadingContext.baseURI == AppConstants.BROWSER_CHROME_URL &&
1790
gBlockedChromePages.some(function(fileName) {
1791
return contentLocation.filePath.endsWith(fileName);
1792
})
1793
) {
1794
return Ci.nsIContentPolicy.REJECT_REQUEST;
1795
}
1796
return Ci.nsIContentPolicy.ACCEPT;
1797
},
1798
shouldProcess(contentLocation, loadInfo, mimeTypeGuess) {
1799
return Ci.nsIContentPolicy.ACCEPT;
1800
},
1801
classDescription: "Policy Engine Content Policy",
1802
contractID: "@mozilla-org/policy-engine-content-policy-service;1",
1803
classID: Components.ID("{ba7b9118-cabc-4845-8b26-4215d2a59ed7}"),
1804
QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPolicy]),
1805
createInstance(outer, iid) {
1806
return this.QueryInterface(iid);
1807
},
1808
};
1809
1810
function addChromeURLBlocker() {
1811
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
1812
registrar.registerFactory(
1813
ChromeURLBlockPolicy.classID,
1814
ChromeURLBlockPolicy.classDescription,
1815
ChromeURLBlockPolicy.contractID,
1816
ChromeURLBlockPolicy
1817
);
1818
1819
Services.catMan.addCategoryEntry(
1820
"content-policy",
1821
ChromeURLBlockPolicy.contractID,
1822
ChromeURLBlockPolicy.contractID,
1823
false,
1824
true
1825
);
1826
}
1827
1828
function pemToBase64(pem) {
1829
return pem
1830
.replace(/-----BEGIN CERTIFICATE-----/, "")
1831
.replace(/-----END CERTIFICATE-----/, "")
1832
.replace(/[\r\n]/g, "");
1833
}