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