Policies.jsm 49.8 KB
Newer Older
1
2
3
4
5
6
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

7
8
9
10
11
12
13
const { XPCOMUtils } = ChromeUtils.import(
  "resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import(
  "resource://gre/modules/AppConstants.jsm"
);
14
15
16
17
18

XPCOMUtils.defineLazyServiceGetters(this, {
  gCertDB: ["@mozilla.org/security/x509certdb;1", "nsIX509CertDB"],
  gXulStore: ["@mozilla.org/xul/xulstore;1", "nsIXULStore"],
});
19

20
XPCOMUtils.defineLazyModuleGetters(this, {
21
  AddonManager: "resource://gre/modules/AddonManager.jsm",
22
  BookmarksPolicies: "resource:///modules/policies/BookmarksPolicies.jsm",
23
  CustomizableUI: "resource:///modules/CustomizableUI.jsm",
24
  FileUtils: "resource://gre/modules/FileUtils.jsm",
25
26
  ProxyPolicies: "resource:///modules/policies/ProxyPolicies.jsm",
  WebsiteFilter: "resource:///modules/policies/WebsiteFilter.jsm",
27
28
});

29
30
XPCOMUtils.defineLazyGlobalGetters(this, ["File", "FileReader"]);

31
32
const PREF_LOGLEVEL = "browser.policies.loglevel";
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
37
38
39
40
41
42
43
44
  return new ConsoleAPI({
    prefix: "Policies.jsm",
    // tip: set maxLogLevel to "debug" and use log.debug() to create detailed
    // messages during development. See LOG_LEVELS in Console.jsm for details.
    maxLogLevel: "error",
    maxLogLevelPref: PREF_LOGLEVEL,
  });
});

45
var EXPORTED_SYMBOLS = ["Policies"];
46

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*
 * ============================
 * = POLICIES IMPLEMENTATIONS =
 * ============================
 *
 * The Policies object below is where the implementation for each policy
 * happens. An object for each policy should be defined, containing
 * callback functions that will be called by the engine.
 *
 * See the _callbacks object in EnterprisePolicies.js for the list of
 * possible callbacks and an explanation of each.
 *
 * Each callback will be called with two parameters:
 * - manager
 *   This is the EnterprisePoliciesManager singleton object from
 *   EnterprisePolicies.js
 *
 * - param
 *   The parameter defined for this policy in policies-schema.json.
 *   It will be different for each policy. It could be a boolean,
 *   a string, an array or a complex object. All parameters have
 *   been validated according to the schema, and no unknown
 *   properties will be present on them.
 *
 * The callbacks will be bound to their parent policy object.
 */
73
var Policies = {
74
75
76
77
78
79
  "3rdparty": {
    onBeforeAddons(manager, param) {
      manager.setExtensionPolicies(param.Extensions);
    },
  },

80
  AppUpdateURL: {
81
82
    onBeforeAddons(manager, param) {
      setDefaultPref("app.update.url", param.href);
83
    },
84
85
  },

86
  Authentication: {
87
88
    onBeforeAddons(manager, param) {
      if ("SPNEGO" in param) {
89
90
91
92
        setAndLockPref(
          "network.negotiate-auth.trusted-uris",
          param.SPNEGO.join(", ")
        );
93
94
      }
      if ("Delegated" in param) {
95
96
97
98
        setAndLockPref(
          "network.negotiate-auth.delegation-uris",
          param.Delegated.join(", ")
        );
99
100
      }
      if ("NTLM" in param) {
101
102
103
104
        setAndLockPref(
          "network.automatic-ntlm-auth.trusted-uris",
          param.NTLM.join(", ")
        );
105
      }
106
107
      if ("AllowNonFQDN" in param) {
        if (param.AllowNonFQDN.NTLM) {
108
109
110
111
          setAndLockPref(
            "network.automatic-ntlm-auth.allow-non-fqdn",
            param.AllowNonFQDN.NTLM
          );
112
113
        }
        if (param.AllowNonFQDN.SPNEGO) {
114
115
116
117
          setAndLockPref(
            "network.negotiate-auth.allow-non-fqdn",
            param.AllowNonFQDN.SPNEGO
          );
118
119
        }
      }
120
    },
121
122
  },

123
  BlockAboutAddons: {
124
125
    onBeforeUIStartup(manager, param) {
      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
142
    onBeforeUIStartup(manager, param) {
      if (param) {
143
        blockAboutPage(manager, "about:profiles");
144
      }
145
    },
146
147
  },

148
  BlockAboutSupport: {
149
150
    onBeforeUIStartup(manager, param) {
      if (param) {
151
        blockAboutPage(manager, "about:support");
152
      }
153
    },
154
155
  },

156
  Bookmarks: {
157
158
    onAllWindowsRestored(manager, param) {
      BookmarksPolicies.processBookmarks(param);
159
    },
160
161
  },

162
  CaptivePortal: {
163
164
165
166
167
    onBeforeAddons(manager, param) {
      setAndLockPref("network.captive-portal-service.enabled", param);
    },
  },

168
  Certificates: {
169
170
    onBeforeAddons(manager, param) {
      if ("ImportEnterpriseRoots" in param) {
171
172
173
174
        setAndLockPref(
          "security.enterprise_roots.enabled",
          param.ImportEnterpriseRoots
        );
175
      }
176
177
178
179
180
181
      if ("Install" in param) {
        (async () => {
          let dirs = [];
          let platform = AppConstants.platform;
          if (platform == "win") {
            dirs = [
182
              // Ugly, but there is no official way to get %USERNAME\AppData\Roaming\Mozilla.
183
              Services.dirsvc.get("XREUSysExt", Ci.nsIFile).parent,
184
185
              // Even more ugly, but there is no official way to get %USERNAME\AppData\Local\Mozilla.
              Services.dirsvc.get("DefProfLRt", Ci.nsIFile).parent.parent,
186
187
188
189
190
191
192
193
            ];
          } else if (platform == "macosx" || platform == "linux") {
            dirs = [
              // These two keys are named wrong. They return the Mozilla directory.
              Services.dirsvc.get("XREUserNativeManifests", Ci.nsIFile),
              Services.dirsvc.get("XRESysNativeManifests", Ci.nsIFile),
            ];
          }
194
195
196
197
          dirs.unshift(Services.dirsvc.get("XREAppDist", Ci.nsIFile));
          for (let certfilename of param.Install) {
            let certfile;
            try {
198
199
200
              certfile = Cc["@mozilla.org/file/local;1"].createInstance(
                Ci.nsIFile
              );
201
202
203
204
              certfile.initWithPath(certfilename);
            } catch (e) {
              for (let dir of dirs) {
                certfile = dir.clone();
205
206
207
                certfile.append(
                  platform == "linux" ? "certificates" : "Certificates"
                );
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
                certfile.append(certfilename);
                if (certfile.exists()) {
                  break;
                }
              }
            }
            let file;
            try {
              file = await File.createFromNsIFile(certfile);
            } catch (e) {
              log.error(`Unable to find certificate - ${certfilename}`);
              continue;
            }
            let reader = new FileReader();
            reader.onloadend = function() {
              if (reader.readyState != reader.DONE) {
                log.error(`Unable to read certificate - ${certfile.path}`);
                return;
              }
227
228
              let certFile = reader.result;
              let cert;
229
              try {
230
                cert = gCertDB.constructX509(certFile);
231
              } catch (e) {
232
233
234
235
236
237
238
239
240
                try {
                  // It might be PEM instead of DER.
                  cert = gCertDB.constructX509FromBase64(pemToBase64(certFile));
                } catch (ex) {
                  log.error(`Unable to add certificate - ${certfile.path}`);
                }
              }
              let now = Date.now() / 1000;
              if (cert) {
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
                gCertDB.asyncVerifyCertAtTime(
                  cert,
                  0x0008 /* certificateUsageSSLCA */,
                  0,
                  null,
                  now,
                  (aPRErrorCode, aVerifiedChain, aHasEVPolicy) => {
                    if (aPRErrorCode == Cr.NS_OK) {
                      // Certificate is already installed.
                      return;
                    }
                    try {
                      gCertDB.addCert(certFile, "CT,CT,");
                    } catch (e) {
                      // It might be PEM instead of DER.
                      gCertDB.addCertFromBase64(
                        pemToBase64(certFile),
                        "CT,CT,"
                      );
                    }
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
278
279
        const hosts = param.Block.map(url => url.hostname)
          .sort()
          .join("\n");
280
281
        runOncePerModification("clearCookiesForBlockedHosts", hosts, () => {
          for (let blocked of param.Block) {
282
283
284
285
            Services.cookies.removeCookiesWithOriginAttributes(
              "{}",
              blocked.hostname
            );
286
287
288
          }
        });
      }
289

290
291
292
293
294
295
      if (
        param.Default !== undefined ||
        param.AcceptThirdParty !== undefined ||
        param.RejectTracker !== undefined ||
        param.Locked
      ) {
296
297
298
299
        const ACCEPT_COOKIES = 0;
        const REJECT_THIRD_PARTY_COOKIES = 1;
        const REJECT_ALL_COOKIES = 2;
        const REJECT_UNVISITED_THIRD_PARTY = 3;
300
        const REJECT_TRACKER = 4;
301
302
303
304
305

        let newCookieBehavior = ACCEPT_COOKIES;
        if (param.Default !== undefined && !param.Default) {
          newCookieBehavior = REJECT_ALL_COOKIES;
        } else if (param.AcceptThirdParty) {
306
          if (param.AcceptThirdParty == "never") {
307
308
309
310
            newCookieBehavior = REJECT_THIRD_PARTY_COOKIES;
          } else if (param.AcceptThirdParty == "from-visited") {
            newCookieBehavior = REJECT_UNVISITED_THIRD_PARTY;
          }
311
312
        } else if (param.RejectTracker !== undefined && param.RejectTracker) {
          newCookieBehavior = REJECT_TRACKER;
313
314
        }

315
316
317
318
319
        setDefaultPref(
          "network.cookie.cookieBehavior",
          newCookieBehavior,
          param.Locked
        );
320
321
322
323
324
325
326
327
328
329
330
      }

      const KEEP_COOKIES_UNTIL_EXPIRATION = 0;
      const KEEP_COOKIES_UNTIL_END_OF_SESSION = 2;

      if (param.ExpireAtSessionEnd !== undefined || param.Locked) {
        let newLifetimePolicy = KEEP_COOKIES_UNTIL_EXPIRATION;
        if (param.ExpireAtSessionEnd) {
          newLifetimePolicy = KEEP_COOKIES_UNTIL_END_OF_SESSION;
        }

331
332
333
334
335
        setDefaultPref(
          "network.cookie.lifetimePolicy",
          newLifetimePolicy,
          param.Locked
        );
336
      }
337
    },
338
339
  },

340
  DefaultDownloadDirectory: {
341
342
343
344
345
346
347
    onBeforeAddons(manager, param) {
      setDefaultPref("browser.download.dir", replacePathVariables(param));
      // If a custom download directory is being used, just lock folder list to 2.
      setAndLockPref("browser.download.folderList", 2);
    },
  },

348
  DisableAppUpdate: {
349
350
351
    onBeforeAddons(manager, param) {
      if (param) {
        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
366
367
368
369
370
    onBeforeAddons(manager, param) {
      if (param) {
        setAndLockPref("devtools.policy.disabled", true);
        setAndLockPref("devtools.chrome.enabled", false);

        manager.disallowFeature("devtools");
371
372
373
        blockAboutPage(manager, "about:devtools");
        blockAboutPage(manager, "about:debugging");
        blockAboutPage(manager, "about:devtools-toolbox");
374
      }
375
    },
376
377
  },

378
  DisableFeedbackCommands: {
379
380
381
382
    onBeforeUIStartup(manager, param) {
      if (param) {
        manager.disallowFeature("feedbackCommands");
      }
383
    },
384
385
  },

386
  DisableFirefoxAccounts: {
387
388
389
    onBeforeAddons(manager, param) {
      if (param) {
        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
399
        setAndLockPref("extensions.screenshots.disabled", true);
      }
400
    },
401
402
  },

403
  DisableFirefoxStudies: {
404
    onBeforeAddons(manager, param) {
405
      if (param) {
406
        manager.disallowFeature("Shield");
407
408
409
410
411
412
413
414
        setAndLockPref(
          "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons",
          false
        );
        setAndLockPref(
          "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features",
          false
        );
415
      }
416
    },
417
418
  },

419
  DisableForgetButton: {
420
421
    onProfileAfterChange(manager, param) {
      if (param) {
422
        setAndLockPref("privacy.panicButton.enabled", false);
423
      }
424
    },
425
426
  },

427
  DisableFormHistory: {
428
    onBeforeUIStartup(manager, param) {
429
      if (param) {
430
431
        setAndLockPref("browser.formfill.enable", false);
      }
432
    },
433
434
  },

435
  DisableMasterPasswordCreation: {
436
437
438
439
    onBeforeUIStartup(manager, param) {
      if (param) {
        manager.disallowFeature("createMasterPassword");
      }
440
    },
441
442
  },

443
  DisablePocket: {
444
445
446
447
    onBeforeAddons(manager, param) {
      if (param) {
        setAndLockPref("extensions.pocket.enabled", false);
      }
448
    },
449
450
  },

451
  DisablePrivateBrowsing: {
452
453
454
    onBeforeAddons(manager, param) {
      if (param) {
        manager.disallowFeature("privatebrowsing");
455
        blockAboutPage(manager, "about:privatebrowsing", true);
456
457
        setAndLockPref("browser.privatebrowsing.autostart", false);
      }
458
    },
459
460
  },

461
  DisableProfileImport: {
462
463
464
    onBeforeUIStartup(manager, param) {
      if (param) {
        manager.disallowFeature("profileImport");
465
466
467
468
        setAndLockPref(
          "browser.newtabpage.activity-stream.migrationExpired",
          true
        );
469
      }
470
    },
471
472
  },

473
  DisableProfileRefresh: {
474
475
476
477
478
    onBeforeUIStartup(manager, param) {
      if (param) {
        manager.disallowFeature("profileRefresh");
        setAndLockPref("browser.disableResetPrompt", true);
      }
479
    },
480
481
  },

482
  DisableSafeMode: {
483
484
485
486
    onBeforeUIStartup(manager, param) {
      if (param) {
        manager.disallowFeature("safeMode");
      }
487
    },
488
489
  },

490
  DisableSecurityBypass: {
491
    onBeforeUIStartup(manager, param) {
492
      if ("InvalidCertificate" in param) {
493
494
495
496
        setAndLockPref(
          "security.certerror.hideAddException",
          param.InvalidCertificate
        );
497
498
      }

499
      if ("SafeBrowsing" in param) {
500
501
502
503
        setAndLockPref(
          "browser.safebrowsing.allowOverride",
          !param.SafeBrowsing
        );
504
      }
505
    },
506
507
  },

508
  DisableSetDesktopBackground: {
509
510
    onBeforeUIStartup(manager, param) {
      if (param) {
511
        manager.disallowFeature("setDesktopBackground");
512
      }
513
    },
514
515
  },

516
  DisableSystemAddonUpdate: {
517
518
519
520
    onBeforeAddons(manager, param) {
      if (param) {
        manager.disallowFeature("SysAddonUpdate");
      }
521
    },
522
523
  },

524
  DisableTelemetry: {
525
526
527
528
    onBeforeAddons(manager, param) {
      if (param) {
        setAndLockPref("datareporting.healthreport.uploadEnabled", false);
        setAndLockPref("datareporting.policy.dataSubmissionEnabled", false);
529
        blockAboutPage(manager, "about:telemetry");
530
      }
531
    },
532
533
  },

534
  DisplayBookmarksToolbar: {
535
    onBeforeUIStartup(manager, param) {
536
537
538
539
540
      let value = (!param).toString();
      // This policy is meant to change the default behavior, not to force it.
      // If this policy was alreay applied and the user chose to re-hide the
      // bookmarks toolbar, do not show it again.
      runOncePerModification("displayBookmarksToolbar", value, () => {
541
542
543
544
545
546
        gXulStore.setValue(
          BROWSER_DOCUMENT_URL,
          "PersonalToolbar",
          "collapsed",
          value
        );
547
      });
548
    },
549
550
  },

551
  DisplayMenuBar: {
552
    onBeforeUIStartup(manager, param) {
553
      let value = (!param).toString();
554
555
556
      // This policy is meant to change the default behavior, not to force it.
      // If this policy was alreay applied and the user chose to re-hide the
      // menu bar, do not show it again.
557
      runOncePerModification("displayMenuBar", value, () => {
558
559
560
561
562
563
        gXulStore.setValue(
          BROWSER_DOCUMENT_URL,
          "toolbar-menubar",
          "autohide",
          value
        );
564
      });
565
    },
566
567
  },

568
  DNSOverHTTPS: {
569
570
571
    onBeforeAddons(manager, param) {
      if ("Enabled" in param) {
        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
588
589
590
    onBeforeAddons(manager, param) {
      setAndLockPref("browser.download.dir", replacePathVariables(param));
      // If a custom download directory is being used, just lock folder list to 2.
      setAndLockPref("browser.download.folderList", 2);
591
592
593
      // Per Chrome spec, user can't choose to download every time
      // if this is set.
      setAndLockPref("browser.download.useDownloadDir", true);
594
595
596
    },
  },

597
  EnableTrackingProtection: {
598
    onBeforeUIStartup(manager, param) {
599
      if (param.Value) {
600
601
602
603
604
605
606
607
608
609
        setDefaultPref(
          "privacy.trackingprotection.enabled",
          true,
          param.Locked
        );
        setDefaultPref(
          "privacy.trackingprotection.pbmode.enabled",
          true,
          param.Locked
        );
610
      } else {
611
612
        setAndLockPref("privacy.trackingprotection.enabled", false);
        setAndLockPref("privacy.trackingprotection.pbmode.enabled", false);
613
      }
614
    },
615
616
  },

617
  Extensions: {
618
    onBeforeUIStartup(manager, param) {
619
620
      let uninstallingPromise = Promise.resolve();
      if ("Uninstall" in param) {
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
        uninstallingPromise = runOncePerModification(
          "extensionsUninstall",
          JSON.stringify(param.Uninstall),
          async () => {
            // If we're uninstalling add-ons, re-run the extensionsInstall runOnce even if it hasn't
            // changed, which will allow add-ons to be updated.
            Services.prefs.clearUserPref(
              "browser.policies.runOncePerModification.extensionsInstall"
            );
            let addons = await AddonManager.getAddonsByIDs(param.Uninstall);
            for (let addon of addons) {
              if (addon) {
                try {
                  await addon.uninstall();
                } catch (e) {
                  // This can fail for add-ons that can't be uninstalled.
                  log.debug(`Add-on ID (${addon.id}) couldn't be uninstalled.`);
                }
639
640
641
              }
            }
          }
642
        );
643
      }
644
      if ("Install" in param) {
645
646
647
648
649
650
651
        runOncePerModification(
          "extensionsInstall",
          JSON.stringify(param.Install),
          async () => {
            await uninstallingPromise;
            for (let location of param.Install) {
              let uri;
652
              try {
653
654
                // We need to try as a file first because
                // Windows paths are valid URIs.
655
                // This is done for legacy support (old API)
656
657
658
659
                let xpiFile = new FileUtils.File(location);
                uri = Services.io.newFileURI(xpiFile);
              } catch (e) {
                uri = Services.io.newURI(location);
660
              }
661
              installAddonFromURL(uri.spec);
662
            }
663
          }
664
        );
665
666
667
      }
      if ("Locked" in param) {
        for (let ID of param.Locked) {
668
669
          manager.disallowFeature(`uninstall-extension:${ID}`);
          manager.disallowFeature(`disable-extension:${ID}`);
670
671
        }
      }
672
    },
673
674
  },

675
  ExtensionSettings: {
676
    onBeforeAddons(manager, param) {
677
678
679
      try {
        manager.setExtensionSettings(param);
      } catch (e) {
680
        log.error("Invalid ExtensionSettings");
681
682
683
684
685
686
      }
    },
    async onBeforeUIStartup(manager, param) {
      let extensionSettings = param;
      let blockAllExtensions = false;
      if ("*" in extensionSettings) {
687
688
689
690
        if (
          "installation_mode" in extensionSettings["*"] &&
          extensionSettings["*"].installation_mode == "blocked"
        ) {
691
692
693
694
695
696
697
          blockAllExtensions = true;
          // Turn off discovery pane in about:addons
          setAndLockPref("extensions.getAddons.showPane", false);
          // Block about:debugging
          blockAboutPage(manager, "about:debugging");
        }
      }
698
      let { addons } = await AddonManager.getActiveAddons();
699
700
701
702
703
704
705
      let allowedExtensions = [];
      for (let extensionID in extensionSettings) {
        if (extensionID == "*") {
          // Ignore global settings
          continue;
        }
        if ("installation_mode" in extensionSettings[extensionID]) {
706
707
708
709
710
711
          if (
            extensionSettings[extensionID].installation_mode ==
              "force_installed" ||
            extensionSettings[extensionID].installation_mode ==
              "normal_installed"
          ) {
712
713
714
715
            if (!extensionSettings[extensionID].install_url) {
              throw new Error(`Missing install_url for ${extensionID}`);
            }
            if (!addons.find(addon => addon.id == extensionID)) {
716
717
718
719
              installAddonFromURL(
                extensionSettings[extensionID].install_url,
                extensionID
              );
720
721
            }
            manager.disallowFeature(`uninstall-extension:${extensionID}`);
722
723
724
725
            if (
              extensionSettings[extensionID].installation_mode ==
              "force_installed"
            ) {
726
727
728
              manager.disallowFeature(`disable-extension:${extensionID}`);
            }
            allowedExtensions.push(extensionID);
729
730
731
          } else if (
            extensionSettings[extensionID].installation_mode == "allowed"
          ) {
732
            allowedExtensions.push(extensionID);
733
734
735
          } else if (
            extensionSettings[extensionID].installation_mode == "blocked"
          ) {
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
            if (addons.find(addon => addon.id == extensionID)) {
              // Can't use the addon from getActiveAddons since it doesn't have uninstall.
              let addon = await AddonManager.getAddonByID(extensionID);
              try {
                await addon.uninstall();
              } catch (e) {
                // This can fail for add-ons that can't be uninstalled.
                log.debug(`Add-on ID (${addon.id}) couldn't be uninstalled.`);
              }
            }
          }
        }
      }
      if (blockAllExtensions) {
        for (let addon of addons) {
751
752
753
754
755
          if (
            addon.isSystem ||
            addon.isBuiltin ||
            !(addon.scope & AddonManager.SCOPE_PROFILE)
          ) {
756
757
758
759
760
761
762
763
764
765
766
767
768
769
            continue;
          }
          if (!allowedExtensions.includes(addon.id)) {
            try {
              // Can't use the addon from getActiveAddons since it doesn't have uninstall.
              let addonToUninstall = await AddonManager.getAddonByID(addon.id);
              await addonToUninstall.uninstall();
            } catch (e) {
              // This can fail for add-ons that can't be uninstalled.
              log.debug(`Add-on ID (${addon.id}) couldn't be uninstalled.`);
            }
          }
        }
      }
770
771
772
    },
  },

773
  ExtensionUpdate: {
774
775
776
777
778
779
780
    onBeforeAddons(manager, param) {
      if (!param) {
        setAndLockPref("extensions.update.enabled", param);
      }
    },
  },

781
  FirefoxHome: {
782
783
784
    onBeforeAddons(manager, param) {
      let locked = param.Locked || false;
      if ("Search" in param) {
785
786
787
788
789
        setDefaultPref(
          "browser.newtabpage.activity-stream.showSearch",
          param.Search,
          locked
        );
790
791
      }
      if ("TopSites" in param) {
792
793
794
795
796
        setDefaultPref(
          "browser.newtabpage.activity-stream.feeds.topsites",
          param.TopSites,
          locked
        );
797
798
      }
      if ("Highlights" in param) {
799
800
801
802
803
        setDefaultPref(
          "browser.newtabpage.activity-stream.feeds.section.highlights",
          param.Highlights,
          locked
        );
804
805
      }
      if ("Pocket" in param) {
806
807
808
809
810
        setDefaultPref(
          "browser.newtabpage.activity-stream.feeds.section.topstories",
          param.Pocket,
          locked
        );
811
812
      }
      if ("Snippets" in param) {
813
814
815
816
817
        setDefaultPref(
          "browser.newtabpage.activity-stream.feeds.snippets",
          param.Snippets,
          locked
        );
818
819
820
821
      }
    },
  },

822
  FlashPlugin: {
823
    onBeforeUIStartup(manager, param) {
824
      addAllowDenyPermissions("plugin:flash", param.Allow, param.Block);
825
826
827
828
829

      const FLASH_NEVER_ACTIVATE = 0;
      const FLASH_ASK_TO_ACTIVATE = 1;

      let flashPrefVal;
830
      if (param.Default === undefined || param.Default) {
831
832
833
834
835
836
837
838
839
        flashPrefVal = FLASH_ASK_TO_ACTIVATE;
      } else {
        flashPrefVal = FLASH_NEVER_ACTIVATE;
      }
      if (param.Locked) {
        setAndLockPref("plugin.state.flash", flashPrefVal);
      } else if (param.Default !== undefined) {
        setDefaultPref("plugin.state.flash", flashPrefVal);
      }
840
    },
841
842
  },

843
  HardwareAcceleration: {
844
845
846
847
    onBeforeAddons(manager, param) {
      if (!param) {
        setAndLockPref("layers.acceleration.disabled", true);
      }
848
    },
849
850
  },

851
  Homepage: {
852
853
854
855
    onBeforeUIStartup(manager, param) {
      // |homepages| will be a string containing a pipe-separated ('|') list of
      // URLs because that is what the "Home page" section of about:preferences
      // (and therefore what the pref |browser.startup.homepage|) accepts.
856
857
858
859
860
      if (param.URL) {
        let homepages = param.URL.href;
        if (param.Additional && param.Additional.length > 0) {
          homepages += "|" + param.Additional.map(url => url.href).join("|");
        }
861
        setDefaultPref("browser.startup.homepage", homepages, param.Locked);
862
        if (param.Locked) {
863
864
865
866
867
868
869
870
871
872
873
874
          setAndLockPref(
            "pref.browser.homepage.disable_button.current_page",
            true
          );
          setAndLockPref(
            "pref.browser.homepage.disable_button.bookmark_page",
            true
          );
          setAndLockPref(
            "pref.browser.homepage.disable_button.restore_default",
            true
          );
875
        } else {
876
877
          // Clear out old run once modification that is no longer used.
          clearRunOnceModification("setHomepage");
878
        }
879
      }
880
881
882
883
884
885
886
887
888
889
890
891
892
      if (param.StartPage) {
        let prefValue;
        switch (param.StartPage) {
          case "none":
            prefValue = 0;
            break;
          case "homepage":
            prefValue = 1;
            break;
          case "previous-session":
            prefValue = 3;
            break;
        }
893
        setDefaultPref("browser.startup.page", prefValue, param.Locked);
894
      }
895
    },
896
897
  },

898
  InstallAddonsPermission: {
899
    onBeforeUIStartup(manager, param) {
900
901
902
903
904
      if ("Allow" in param) {
        addAllowDenyPermissions("install", param.Allow, null);
      }
      if ("Default" in param) {
        setAndLockPref("xpinstall.enabled", param.Default);
905
        if (!param.Default) {
906
          blockAboutPage(manager, "about:debugging");
907
908
909
910
911
912
913
914
          setAndLockPref(
            "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons",
            false
          );
          setAndLockPref(
            "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features",
            false
          );
915
          manager.disallowFeature("xpinstall");
916
        }
917
      }
918
    },
919
920
  },

921
  LocalFileLinks: {
922
923
    onBeforeAddons(manager, param) {
      // If there are existing capabilities, lock them with the policy pref.
924
925
926
      let policyNames = Services.prefs
        .getCharPref("capability.policy.policynames", "")
        .split(" ");
927
928
      policyNames.push("localfilelinks_policy");
      setAndLockPref("capability.policy.policynames", policyNames.join(" "));
929
930
931
932
933
934
935
936
      setAndLockPref(
        "capability.policy.localfilelinks_policy.checkloaduri.enabled",
        "allAccess"
      );
      setAndLockPref(
        "capability.policy.localfilelinks_policy.sites",
        param.join(" ")
      );
937
938
939
    },
  },

940
  NetworkPrediction: {
941
942
943
944
945
946
    onBeforeAddons(manager, param) {
      setAndLockPref("network.dns.disablePrefetch", !param);
      setAndLockPref("network.dns.disablePrefetchFromHTTPS", !param);
    },
  },

947
  NewTabPage: {
948
949
950
951
952
    onBeforeAddons(manager, param) {
      setAndLockPref("browser.newtabpage.enabled", param);
    },
  },

953
  NoDefaultBookmarks: {
954
955
956
957
    onProfileAfterChange(manager, param) {
      if (param) {
        manager.disallowFeature("defaultBookmarks");
      }
958
    },
959
960
  },

961
  OfferToSaveLogins: {
962
963
    onBeforeUIStartup(manager, param) {
      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
979
980
981
982
      setAndLockPref("startup.homepage_override_url", url);
      // The pref startup.homepage_override_url is only used
      // as a fallback when the update.xml file hasn't provided
      // a specific post-update URL.
      manager.disallowFeature("postUpdateCustomPage");
983
    },
984
985
  },

986
  Permissions: {
987
988
    onBeforeUIStartup(manager, param) {
      if (param.Camera) {
989
990
991
992
993
        addAllowDenyPermissions(
          "camera",
          param.Camera.Allow,
          param.Camera.Block
        );
994
995
996
997
        setDefaultPermission("camera", param.Camera);
      }

      if (param.Microphone) {
998
999
1000
        addAllowDenyPermissions(
          "microphone",
          param.Microphone.Allow,