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