diff --git a/toolkit/components/extensions/ext-management.js b/toolkit/components/extensions/ext-management.js index da863017fac7..fcafe68988e5 100644 --- a/toolkit/components/extensions/ext-management.js +++ b/toolkit/components/extensions/ext-management.js @@ -2,8 +2,60 @@ /* vim: set sts=2 sw=2 et tw=80: */ "use strict"; +XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", + "resource://gre/modules/AddonManager.jsm"); + +function installType(addon) { + if (addon.temporarilyInstalled) { + return "development"; + } else if (addon.foreignInstall) { + return "sideload"; + } else if (addon.isSystem) { + return "other"; + } + return "normal"; +} + extensions.registerSchemaAPI("management", (extension, context) => { return { - management: {}, + management: { + getSelf: function() { + return new Promise((resolve, reject) => AddonManager.getAddonByID(extension.id, addon => { + try { + let m = extension.manifest; + let extInfo = { + id: extension.id, + name: addon.name, + shortName: m.short_name || "", + description: addon.description || "", + version: addon.version, + mayDisable: !!(addon.permissions & AddonManager.PERM_CAN_DISABLE), + enabled: addon.isActive, + optionsUrl: addon.optionsURL || "", + permissions: Array.from(extension.permissions).filter(perm => { + return !extension.whiteListedHosts.pat.includes(perm); + }), + hostPermissions: extension.whiteListedHosts.pat, + installType: installType(addon), + }; + if (addon.homepageURL) { + extInfo.homepageUrl = addon.homepageURL; + } + if (addon.updateURL) { + extInfo.updateUrl = addon.updateURL; + } + if (m.icons) { + extInfo.icons = Object.keys(m.icons).map(key => { + return {size: Number(key), url: m.icons[key]}; + }); + } + + resolve(extInfo); + } catch (e) { + reject(e); + } + })); + }, + }, }; }); diff --git a/toolkit/components/extensions/schemas/management.json b/toolkit/components/extensions/schemas/management.json index 5b55f55877ae..99927b75ceae 100644 --- a/toolkit/components/extensions/schemas/management.json +++ b/toolkit/components/extensions/schemas/management.json @@ -198,7 +198,6 @@ { "name": "getSelf", "type": "function", - "unsupported": true, "description": "Returns information about the calling extension. Note: This function can be used without requesting the 'management' permission in the manifest.", "async": "callback", "parameters": [ diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_ext_management.js b/toolkit/mozapps/extensions/test/xpcshell/test_ext_management.js new file mode 100644 index 000000000000..a3b3f477c852 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_ext_management.js @@ -0,0 +1,137 @@ +"use strict"; + +add_task(function* setup() { + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "48", "48"); + startupManager(); +}); + +/* eslint-disable no-undef */ +// Shared background function for getSelf tests +function backgroundGetSelf() { + browser.management.getSelf().then(extInfo => { + browser.test.sendMessage("management-getSelf", extInfo); + }, error => { + browser.test.notifyFail(`getSelf rejected with error: ${error}`); + }); +} +/* eslint-enable no-undef */ + +add_task(function* test_management_get_self_complete() { + const id = "get_self_test_complete@tests.mozilla.com"; + const permissions = ["management", "cookies"]; + const hostPermissions = ["*://example.org/", "https://foo.example.org/"]; + + let manifest = { + applications: { + gecko: { + id, + update_url: "https://updates.mozilla.com/", + }, + }, + name: "test extension name", + short_name: "test extension short name", + description: "test extension description", + version: "1.0", + homepage_url: "http://www.example.com/", + options_ui: { + "page": "get_self_options.html", + }, + icons: { + "16": "icons/icon-16.png", + "48": "icons/icon-48.png", + }, + permissions: [...permissions, ...hostPermissions], + }; + + let extension = ExtensionTestUtils.loadExtension({ + manifest, + background: backgroundGetSelf, + useAddonManager: "temporary", + }); + yield extension.startup(); + let extInfo = yield extension.awaitMessage("management-getSelf"); + + equal(extInfo.id, id, "getSelf returned the expected id"); + equal(extInfo.installType, "development", "getSelf returned the expected installType"); + for (let prop of ["name", "description", "version"]) { + equal(extInfo[prop], manifest[prop], `getSelf returned the expected ${prop}`); + } + equal(extInfo.shortName, manifest.short_name, "getSelf returned the expected shortName"); + equal(extInfo.mayDisable, true, "getSelf returned the expected value for mayDisable"); + equal(extInfo.enabled, true, "getSelf returned the expected value for enabled"); + equal(extInfo.homepageUrl, manifest.homepage_url, "getSelf returned the expected homepageUrl"); + equal(extInfo.updateUrl, manifest.applications.gecko.update_url, "getSelf returned the expected updateUrl"); + ok(extInfo.optionsUrl.endsWith(manifest.options_ui.page), "getSelf returned the expected optionsUrl"); + for (let [index, size] of Object.keys(manifest.icons).sort().entries()) { + equal(extInfo.icons[index].size, +size, "getSelf returned the expected icon size"); + equal(extInfo.icons[index].url, manifest.icons[size], "getSelf returned the expected icon url"); + } + deepEqual(extInfo.permissions.sort(), permissions.sort(), "getSelf returned the expected permissions"); + deepEqual(extInfo.hostPermissions.sort(), hostPermissions.sort(), "getSelf returned the expected hostPermissions"); + equal(extInfo.installType, "development", "getSelf returned the expected installType"); + yield extension.unload(); +}); + +add_task(function* test_management_get_self_minimal() { + const id = "get_self_test_minimal@tests.mozilla.com"; + + let manifest = { + applications: { + gecko: { + id, + }, + }, + name: "test extension name", + version: "1.0", + }; + + let extension = ExtensionTestUtils.loadExtension({ + manifest, + background: backgroundGetSelf, + useAddonManager: "temporary", + }); + yield extension.startup(); + let extInfo = yield extension.awaitMessage("management-getSelf"); + + equal(extInfo.id, id, "getSelf returned the expected id"); + equal(extInfo.installType, "development", "getSelf returned the expected installType"); + for (let prop of ["name", "version"]) { + equal(extInfo[prop], manifest[prop], `getSelf returned the expected ${prop}`); + } + for (let prop of ["shortName", "description", "optionsUrl"]) { + equal(extInfo[prop], "", `getSelf returned the expected ${prop}`); + } + for (let prop of ["homepageUrl", " updateUrl", "icons"]) { + equal(Reflect.getOwnPropertyDescriptor(extInfo, prop), undefined, `getSelf did not return a ${prop} property`); + } + for (let prop of ["permissions", "hostPermissions"]) { + deepEqual(extInfo[prop], [], `getSelf returned the expected ${prop}`); + } + yield extension.unload(); +}); + +add_task(function* test_management_get_self_permanent() { + const id = "get_self_test_permanent@tests.mozilla.com"; + + let manifest = { + applications: { + gecko: { + id, + }, + }, + name: "test extension name", + version: "1.0", + }; + + let extension = ExtensionTestUtils.loadExtension({ + manifest, + background: backgroundGetSelf, + useAddonManager: "permanent", + }); + yield extension.startup(); + let extInfo = yield extension.awaitMessage("management-getSelf"); + + equal(extInfo.id, id, "getSelf returned the expected id"); + equal(extInfo.installType, "normal", "getSelf returned the expected installType"); + yield extension.unload(); +}); diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini index 6b34c36b9fca..3c3aa067c53f 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini @@ -319,3 +319,5 @@ skip-if = os != "win" # Bug 1246231 skip-if = os == "mac" && debug [test_softblocked.js] +[test_ext_management.js] +