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