summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_ext_permissions_uninstall.js
blob: d123575cc51cf699cdadfa4e6a09745983348863 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"use strict";

const { ExtensionPermissions } = ChromeUtils.importESModule(
  "resource://gre/modules/ExtensionPermissions.sys.mjs"
);

AddonTestUtils.init(this);
AddonTestUtils.overrideCertDB();
AddonTestUtils.createAppInfo(
  "xpcshell@tests.mozilla.org",
  "XPCShell",
  "1",
  "42"
);

// This test doesn't need the test extensions to be detected as privileged,
// disabling it to avoid having to keep the list of expected "internal:*"
// permissions that are added automatically to privileged extensions
// and already covered by other tests.
AddonTestUtils.usePrivilegedSignatures = false;

// Look up the cached permissions, if any.
async function getCachedPermissions(extensionId) {
  const NotFound = Symbol("extension ID not found in permissions cache");
  try {
    return await ExtensionParent.StartupCache.permissions.get(
      extensionId,
      () => {
        // Throw error to prevent the key from being created.
        throw NotFound;
      }
    );
  } catch (e) {
    if (e === NotFound) {
      return null;
    }
    throw e;
  }
}

// Look up the permissions from the file. Internal methods are used to avoid
// inadvertently changing the permissions in the cache or the database.
async function getStoredPermissions(extensionId) {
  if (await ExtensionPermissions._has(extensionId)) {
    return ExtensionPermissions._get(extensionId);
  }
  return null;
}

add_task(async function setup() {
  // Bug 1646182: Force ExtensionPermissions to run in rkv mode, the legacy
  // storage mode will run in xpcshell-legacy-ep.ini
  await ExtensionPermissions._uninit();

  optionalPermissionsPromptHandler.init();
  optionalPermissionsPromptHandler.acceptPrompt = true;

  await AddonTestUtils.promiseStartupManager();
  registerCleanupFunction(async () => {
    await AddonTestUtils.promiseShutdownManager();
  });
});

// This test must run before any restart of the addonmanager so the
// ExtensionAddonObserver works.
add_task(async function test_permissions_removed() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      optional_permissions: ["idle"],
    },
    background() {
      browser.test.onMessage.addListener(async (msg, arg) => {
        if (msg == "request") {
          try {
            let result = await browser.permissions.request(arg);
            browser.test.sendMessage("request.result", result);
          } catch (err) {
            browser.test.sendMessage("request.result", err.message);
          }
        }
      });
    },
    useAddonManager: "temporary",
  });

  await extension.startup();

  await withHandlingUserInput(extension, async () => {
    extension.sendMessage("request", { permissions: ["idle"], origins: [] });
    let result = await extension.awaitMessage("request.result");
    equal(result, true, "request() for optional permissions succeeded");
  });

  let id = extension.id;
  let perms = await ExtensionPermissions.get(id);
  equal(
    perms.permissions.length,
    1,
    `optional permission added (${JSON.stringify(perms.permissions)})`
  );

  Assert.deepEqual(
    await getCachedPermissions(id),
    {
      permissions: ["idle"],
      origins: [],
    },
    "Optional permission added to cache"
  );
  Assert.deepEqual(
    await getStoredPermissions(id),
    {
      permissions: ["idle"],
      origins: [],
    },
    "Optional permission added to persistent file"
  );

  await extension.unload();

  // Directly read from the internals instead of using ExtensionPermissions.get,
  // because the latter will lazily cache the extension ID.
  Assert.deepEqual(
    await getCachedPermissions(id),
    null,
    "Cached permissions removed"
  );
  Assert.deepEqual(
    await getStoredPermissions(id),
    null,
    "Stored permissions removed"
  );

  perms = await ExtensionPermissions.get(id);
  equal(
    perms.permissions.length,
    0,
    `no permissions after uninstall (${JSON.stringify(perms.permissions)})`
  );
  equal(
    perms.origins.length,
    0,
    `no origin permissions after uninstall (${JSON.stringify(perms.origins)})`
  );

  // The public ExtensionPermissions.get method should not store (empty)
  // permissions in the persistent database. Polluting the cache is not ideal,
  // but acceptable since the cache will eventually be cleared, and non-test
  // code is not likely to call ExtensionPermissions.get() for non-installed
  // extensions anyway.
  Assert.deepEqual(await getCachedPermissions(id), perms, "Permissions cached");
  Assert.deepEqual(
    await getStoredPermissions(id),
    null,
    "Permissions not saved"
  );
});