gecko-dev/toolkit/components/extensions/test/xpcshell/test_WebExtensionPolicy.js
Kris Maglione d9d83b9f73 Bug 1322235: Part 4 - Add initial native WebExtensionPolicy bindings. r=billm,aswan
Bill, can you please review the binding code and the general sanity of the
platform code? Andrew and zombie, can you please review the policy logic and
tests?

As in part 1, this aims to reduce the overhead of our extension policy logic
by making it directly available to native code with as little JS and XPConnect
overhead as possible.

MozReview-Commit-ID: 40m1wSEYtBo

--HG--
extra : rebase_source : c03834791707f78431440af9b88035ab03dc9564
2017-05-24 15:58:19 -07:00

140 lines
5.3 KiB
JavaScript

/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
const {newURI} = Services.io;
add_task(async function test_WebExtensinonPolicy() {
const id = "foo@bar.baz";
const uuid = "ca9d3f23-125c-4b24-abfc-1ca2692b0610";
const baseURL = "file:///foo/";
const mozExtURL = `moz-extension://${uuid}/`;
const mozExtURI = newURI(mozExtURL);
let policy = new WebExtensionPolicy({
id,
mozExtensionHostname: uuid,
baseURL,
localizeCallback(str) {
return `<${str}>`;
},
allowedOrigins: new MatchPatternSet(["http://foo.bar/", "*://*.baz/"], {ignorePath: true}),
permissions: ["<all_urls>"],
webAccessibleResources: ["/foo/*", "/bar.baz"].map(glob => new MatchGlob(glob)),
});
equal(policy.active, false, "Active attribute should initially be false");
// GetURL
equal(policy.getURL(), mozExtURL, "getURL() should return the correct root URL");
equal(policy.getURL("path/foo.html"), `${mozExtURL}path/foo.html`, "getURL(path) should return the correct URL");
// Permissions
deepEqual(policy.permissions, ["<all_urls>"], "Initial permissions should be correct");
ok(policy.hasPermission("<all_urls>"), "hasPermission should match existing permission");
ok(!policy.hasPermission("history"), "hasPermission should not match nonexistent permission");
Assert.throws(() => { policy.permissions[0] = "foo"; },
TypeError,
"Permissions array should be frozen");
policy.permissions = ["history"];
deepEqual(policy.permissions, ["history"], "Permissions should be updateable as a set");
ok(policy.hasPermission("history"), "hasPermission should match existing permission");
ok(!policy.hasPermission("<all_urls>"), "hasPermission should not match nonexistent permission");
// Origins
ok(policy.canAccessURI(newURI("http://foo.bar/quux")), "Should be able to access whitelisted URI");
ok(policy.canAccessURI(newURI("https://x.baz/foo")), "Should be able to access whitelisted URI");
ok(!policy.canAccessURI(newURI("https://foo.bar/quux")), "Should not be able to access non-whitelisted URI");
policy.allowedOrigins = new MatchPatternSet(["https://foo.bar/"], {ignorePath: true});
ok(policy.canAccessURI(newURI("https://foo.bar/quux")), "Should be able to access updated whitelisted URI");
ok(!policy.canAccessURI(newURI("https://x.baz/foo")), "Should not be able to access removed whitelisted URI");
// Web-accessible resources
ok(policy.isPathWebAccessible("/foo/bar"), "Web-accessible glob should be web-accessible");
ok(policy.isPathWebAccessible("/bar.baz"), "Web-accessible path should be web-accessible");
ok(!policy.isPathWebAccessible("/bar.baz/quux"), "Non-web-accessible path should not be web-accessible");
// Localization
equal(policy.localize("foo"), "<foo>", "Localization callback should work as expected");
// Protocol and lookups.
let proto = Services.io.getProtocolHandler("moz-extension", uuid).QueryInterface(Ci.nsISubstitutingProtocolHandler);
deepEqual(WebExtensionPolicy.getActiveExtensions(), [], "Should have no active extensions");
equal(WebExtensionPolicy.getByID(id), null, "ID lookup should not return extension when not active");
equal(WebExtensionPolicy.getByHostname(uuid), null, "Hostname lookup should not return extension when not active");
Assert.throws(() => proto.resolveURI(mozExtURI), /NS_ERROR_NOT_AVAILABLE/,
"URL should not resolve when not active");
policy.active = true;
equal(policy.active, true, "Active attribute should be updated");
let exts = WebExtensionPolicy.getActiveExtensions();
equal(exts.length, 1, "Should have one active extension");
equal(exts[0], policy, "Should have the correct active extension");
equal(WebExtensionPolicy.getByID(id), policy, "ID lookup should return extension when active");
equal(WebExtensionPolicy.getByHostname(uuid), policy, "Hostname lookup should return extension when active");
equal(proto.resolveURI(mozExtURI), baseURL, "URL should resolve correctly while active");
policy.active = false;
equal(policy.active, false, "Active attribute should be updated");
deepEqual(WebExtensionPolicy.getActiveExtensions(), [], "Should have no active extensions");
equal(WebExtensionPolicy.getByID(id), null, "ID lookup should not return extension when not active");
equal(WebExtensionPolicy.getByHostname(uuid), null, "Hostname lookup should not return extension when not active");
Assert.throws(() => proto.resolveURI(mozExtURI), /NS_ERROR_NOT_AVAILABLE/,
"URL should not resolve when not active");
// Conflicting policies.
// This asserts in debug builds, so only test in non-debug builds.
if (!AppConstants.DEBUG) {
policy.active = true;
let attrs = [{id, uuid},
{id, uuid: "d916886c-cfdf-482e-b7b1-d7f5b0facfa5"},
{id: "foo@quux", uuid}];
// eslint-disable-next-line no-shadow
for (let {id, uuid} of attrs) {
let policy2 = new WebExtensionPolicy({
id,
mozExtensionHostname: uuid,
baseURL: "file://bar/",
localizeCallback() {},
allowedOrigins: new MatchPatternSet([]),
});
Assert.throws(() => { policy2.active = true; }, /NS_ERROR_UNEXPECTED/,
`Should not be able to activate conflicting policy: ${id} ${uuid}`);
}
policy.active = false;
}
});