Policies.jsm 49.9 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
390
    onBeforeAddons(manager, param) {
      if (param) {
        setAndLockPref("identity.fxaccounts.enabled", false);
      }
391
    },
392
393
  },

394
  DisableFirefoxScreenshots: {
395
    onBeforeAddons(manager, param) {
396
      if (param) {
397
398
        setAndLockPref("extensions.screenshots.disabled", true);
      }
399
    },
400
401
  },

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

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

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

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

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

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

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

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

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

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

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

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

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

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

533
  DisplayBookmarksToolbar: {
534
    onBeforeUIStartup(manager, param) {
535
536
537
538
539
      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, () => {
540
541
542
543
544
545
        gXulStore.setValue(
          BROWSER_DOCUMENT_URL,
          "PersonalToolbar",
          "collapsed",
          value
        );
546
      });
547
    },
548
549
  },

550
  DisplayMenuBar: {
551
    onBeforeUIStartup(manager, param) {
552
      let value = (!param).toString();
553
554
555
      // 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.
556
      runOncePerModification("displayMenuBar", value, () => {
557
558
559
560
561
562
        gXulStore.setValue(
          BROWSER_DOCUMENT_URL,
          "toolbar-menubar",
          "autohide",
          value
        );
563
      });
564
    },
565
566
  },

567
  DNSOverHTTPS: {
568
569
570
    onBeforeAddons(manager, param) {
      if ("Enabled" in param) {
        let mode = param.Enabled ? 2 : 5;
571
        setDefaultPref("network.trr.mode", mode, param.Locked);
572
573
      }
      if (param.ProviderURL) {
574
        setDefaultPref("network.trr.uri", param.ProviderURL.href, param.Locked);
575
576
577
578
      }
    },
  },

579
  DontCheckDefaultBrowser: {
580
    onBeforeUIStartup(manager, param) {
581
      setAndLockPref("browser.shell.checkDefaultBrowser", !param);
582
    },
583
584
  },

585
  DownloadDirectory: {
586
587
588
589
    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);
590
591
592
      // Per Chrome spec, user can't choose to download every time
      // if this is set.
      setAndLockPref("browser.download.useDownloadDir", true);
593
594
595
    },
  },

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

616
  Extensions: {
617
    onBeforeUIStartup(manager, param) {
618
619
      let uninstallingPromise = Promise.resolve();
      if ("Uninstall" in param) {
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
        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.`);
                }
638
639
640
              }
            }
          }
641
        );
642
      }
643
      if ("Install" in param) {
644
645
646
647
648
649
650
        runOncePerModification(
          "extensionsInstall",
          JSON.stringify(param.Install),
          async () => {
            await uninstallingPromise;
            for (let location of param.Install) {
              let uri;
651
              try {
652
653
654
655
656
657
658
659
660
661
662
663
                uri = Services.io.newURI(location);
              } catch (e) {
                // If it's not a URL, it's probably a file path.
                // Assume location is a file path
                // This is done for legacy support (old API)
                try {
                  let xpiFile = new FileUtils.File(location);
                  uri = Services.io.newFileURI(xpiFile);
                } catch (ex) {
                  log.error(`Invalid extension path location - ${location}`);
                  return;
                }
664
              }
665
              installAddonFromURL(uri.spec);
666
            }
667
          }
668
        );
669
670
671
      }
      if ("Locked" in param) {
        for (let ID of param.Locked) {
672
673
          manager.disallowFeature(`uninstall-extension:${ID}`);
          manager.disallowFeature(`disable-extension:${ID}`);
674
675
        }
      }
676
    },
677
678
  },

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

777
  ExtensionUpdate: {
778
779
780
781
782
783
784
    onBeforeAddons(manager, param) {
      if (!param) {
        setAndLockPref("extensions.update.enabled", param);
      }
    },
  },

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

826
  FlashPlugin: {
827
    onBeforeUIStartup(manager, param) {
828
      addAllowDenyPermissions("plugin:flash", param.Allow, param.Block);
829
830
831
832
833

      const FLASH_NEVER_ACTIVATE = 0;
      const FLASH_ASK_TO_ACTIVATE = 1;

      let flashPrefVal;
834
      if (param.Default === undefined || param.Default) {
835
836
837
838
839
840
841
842
843
        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);
      }
844
    },
845
846
  },

847
  HardwareAcceleration: {
848
849
850
851
    onBeforeAddons(manager, param) {
      if (!param) {
        setAndLockPref("layers.acceleration.disabled", true);
      }
852
    },
853
854
  },

855
  Homepage: {
856
857
858
859
    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.
860
861
862
863
864
      if (param.URL) {
        let homepages = param.URL.href;
        if (param.Additional && param.Additional.length > 0) {
          homepages += "|" + param.Additional.map(url => url.href).join("|");
        }
865
        setDefaultPref("browser.startup.homepage", homepages, param.Locked);
866
        if (param.Locked) {
867
868
869
870
871
872
873
874
875
876
877
878
          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
          );
879
880
881
882
883
        } else {
          runOncePerModification("setHomepage", homepages, () => {
            Services.prefs.clearUserPref("browser.startup.homepage");
          });
        }
884
      }
885
886
887
888
889
890
891
892
893
894
895
896
897
      if (param.StartPage) {
        let prefValue;
        switch (param.StartPage) {
          case "none":
            prefValue = 0;
            break;
          case "homepage":
            prefValue = 1;
            break;
          case "previous-session":
            prefValue = 3;
            break;
        }
898
        setDefaultPref("browser.startup.page", prefValue, param.Locked);
899
      }
900
    },
901
902
  },

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

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

945
  NetworkPrediction: {
946
947
948
949
950
951
    onBeforeAddons(manager, param) {
      setAndLockPref("network.dns.disablePrefetch", !param);
      setAndLockPref("network.dns.disablePrefetchFromHTTPS", !param);
    },
  },

952
  NewTabPage: {
953
954
955
956
957
    onBeforeAddons(manager, param) {
      setAndLockPref("browser.newtabpage.enabled", param);
    },
  },

958
  NoDefaultBookmarks: {
959
960
961
962
    onProfileAfterChange(manager, param) {
      if (param) {
        manager.disallowFeature("defaultBookmarks");
      }
963
    },
964
965
  },

966
  OfferToSaveLogins: {
967
968
    onBeforeUIStartup(manager, param) {
      setAndLockPref("signon.rememberSignons", param);
969
    },
970
971
  },

972
  OverrideFirstRunPage: {
973
    onProfileAfterChange(manager, param) {
974
      let url = param ? param.href : "";
975
      setAndLockPref("startup.homepage_welcome_url", url);
976
    },
977
978
  },

979
  OverridePostUpdatePage: {
980
    onProfileAfterChange(manager, param) {
981
      let url = param ? param.href : "";
982
983
984
985
986
      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");
987
    },
988
989
  },

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