Skip to content

Commit

Permalink
Bug 1314361 - Part 2: Stop using addonId origin attribute for permiss…
Browse files Browse the repository at this point in the history
…ion checks. r=billm
  • Loading branch information
kmaglione committed Nov 4, 2016
1 parent 4a47aea commit 9f1b643
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 43 deletions.
15 changes: 11 additions & 4 deletions caps/BasePrincipal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -615,15 +615,19 @@ BasePrincipal::GetUnknownAppId(bool* aUnknownAppId)
bool
BasePrincipal::AddonHasPermission(const nsAString& aPerm)
{
if (mOriginAttributes.mAddonId.IsEmpty()) {
nsAutoString addonId;
NS_ENSURE_SUCCESS(GetAddonId(addonId), false);

if (addonId.IsEmpty()) {
return false;
}

nsCOMPtr<nsIAddonPolicyService> aps =
do_GetService("@mozilla.org/addons/policy-service;1");
NS_ENSURE_TRUE(aps, false);

bool retval = false;
nsresult rv = aps->AddonHasPermission(mOriginAttributes.mAddonId, aPerm, &retval);
nsresult rv = aps->AddonHasPermission(addonId, aPerm, &retval);
NS_ENSURE_SUCCESS(rv, false);
return retval;
}
Expand Down Expand Up @@ -702,15 +706,18 @@ BasePrincipal::CloneStrippingUserContextIdAndFirstPartyDomain()
bool
BasePrincipal::AddonAllowsLoad(nsIURI* aURI, bool aExplicit /* = false */)
{
if (mOriginAttributes.mAddonId.IsEmpty()) {
nsAutoString addonId;
NS_ENSURE_SUCCESS(GetAddonId(addonId), false);

if (addonId.IsEmpty()) {
return false;
}

nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
NS_ENSURE_TRUE(aps, false);

bool allowed = false;
nsresult rv = aps->AddonMayLoadURI(mOriginAttributes.mAddonId, aURI, aExplicit, &allowed);
nsresult rv = aps->AddonMayLoadURI(addonId, aURI, aExplicit, &allowed);
return NS_SUCCEEDED(rv) && allowed;
}

Expand Down
42 changes: 15 additions & 27 deletions caps/tests/mochitest/test_addonMayLoad.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
let aps = Cc["@mozilla.org/addons/policy-service;1"].getService(Ci.nsIAddonPolicyService).wrappedJSObject;

SimpleTest.waitForExplicitFinish();
let oldAddonIdCallback = aps.setExtensionURIToAddonIdCallback(uri => uri.host);
SimpleTest.registerCleanupFunction(function() {
aps.setAddonLoadURICallback('addonA', null);
aps.setAddonLoadURICallback('addonB', null);
aps.setAddonLoadURICallback('addona', null);
aps.setAddonLoadURICallback('addonb', null);
aps.setExtensionURIToAddonIdCallback(oldAddonIdCallback);
});

function tryLoad(sb, uri) {
Expand All @@ -39,42 +41,28 @@
return p;
}

let exampleCom_addonA = new Cu.Sandbox(ssm.createCodebasePrincipal(Services.io.newURI('http://example.com'), {addonId: 'addonA'}),
{wantGlobalProperties: ['XMLHttpRequest']});
let nullPrin_addonA = new Cu.Sandbox(ssm.createNullPrincipal({addonId: 'addonA'}),
{wantGlobalProperties: ['XMLHttpRequest']});
let exampleCom_addonB = new Cu.Sandbox(ssm.createCodebasePrincipal(Services.io.newURI('http://example.com'), {addonId: 'addonB'}),
{wantGlobalProperties: ['XMLHttpRequest']});
let addonA = new Cu.Sandbox(ssm.createCodebasePrincipal(Services.io.newURI('moz-extension://addonA/'), {}),
{wantGlobalProperties: ['XMLHttpRequest']});
let addonB = new Cu.Sandbox(ssm.createCodebasePrincipal(Services.io.newURI('moz-extension://addonB/'), {}),
{wantGlobalProperties: ['XMLHttpRequest']});

function uriForDomain(d) { return d + '/tests/caps/tests/mochitest/file_data.txt' }

tryLoad(exampleCom_addonA, uriForDomain('http://example.com'))
tryLoad(addonA, uriForDomain('http://test1.example.org'))
.then(function(success) {
ok(success, "same-origin load should succeed for addon A");
return tryLoad(nullPrin_addonA, uriForDomain('http://example.com'));
}).then(function(success) {
ok(!success, "null-principal load should fail for addon A");
return tryLoad(exampleCom_addonB, uriForDomain('http://example.com'));
}).then(function(success) {
ok(success, "same-origin load should succeed for addon B");
return tryLoad(exampleCom_addonA, uriForDomain('http://test1.example.org'));
}).then(function(success) {
ok(!success, "cross-origin load should fail for addon A");
aps.setAddonLoadURICallback('addonA', function(uri) { return /test1/.test(uri.host); });
aps.setAddonLoadURICallback('addonB', function(uri) { return /test2/.test(uri.host); });
return tryLoad(exampleCom_addonA, uriForDomain('http://test1.example.org'));
aps.setAddonLoadURICallback('addona', function(uri) { return /test1/.test(uri.host); });
aps.setAddonLoadURICallback('addonb', function(uri) { return /test2/.test(uri.host); });
return tryLoad(addonA, uriForDomain('http://test1.example.org'));
}).then(function(success) {
ok(success, "whitelisted cross-origin load of test1 should succeed for addon A");
return tryLoad(nullPrin_addonA, uriForDomain('http://test1.example.org'));
}).then(function(success) {
ok(!success, "whitelisted null principal load of test1 should still fail for addon A");
return tryLoad(exampleCom_addonB, uriForDomain('http://test1.example.org'));
return tryLoad(addonB, uriForDomain('http://test1.example.org'));
}).then(function(success) {
ok(!success, "non-whitelisted cross-origin load of test1 should fail for addon B");
return tryLoad(exampleCom_addonB, uriForDomain('http://test2.example.org'));
return tryLoad(addonB, uriForDomain('http://test2.example.org'));
}).then(function(success) {
ok(success, "whitelisted cross-origin load of test2 should succeed for addon B");
return tryLoad(exampleCom_addonA, uriForDomain('http://test2.example.org'));
return tryLoad(addonA, uriForDomain('http://test2.example.org'));
}).then(function(success) {
ok(!success, "non-whitelisted cross-origin load of test2 should fail for addon A");
SimpleTest.finish();
Expand Down
2 changes: 1 addition & 1 deletion caps/tests/mochitest/test_extensionURL.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
is(stripTrailingSlash(prin.URI.spec), url, 'Principal uri is correct: ' + url);
function stripPath(s) { return s.replace(/(.*\/\/.+)\/.*/, '$1'); };
is(prin.originNoSuffix, stripPath(url), 'Principal origin is correct: ' + prin.originNoSuffix);
is(prin.originAttributes.addonId, 'imaginaryaddon-' + url[url.indexOf('/') + 2], 'addonId is correct');
is(prin.addonId, 'imaginaryaddon-' + url[url.indexOf('/') + 2], 'addonId is correct');
if (/_blank/.test(url)) {
is(SpecialPowers.wrap(ifr.contentWindow).document.documentElement.innerHTML,
'<head></head><body></body>', 'blank document looks right');
Expand Down
2 changes: 1 addition & 1 deletion devtools/server/actors/tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ TabActor.prototype = {
}

// Collect the addonID from the document origin attributes.
let addonID = window.document.nodePrincipal.originAttributes.addonId;
let addonID = window.document.nodePrincipal.addonId;

return {
id,
Expand Down
2 changes: 1 addition & 1 deletion devtools/server/actors/webextension.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ WebExtensionActor.prototype._shouldAddNewGlobalAsDebuggee = function (newGlobal)
const global = unwrapDebuggerObjectGlobal(newGlobal);

if (global instanceof Ci.nsIDOMWindow) {
return global.document.nodePrincipal.originAttributes.addonId == this.id;
return global.document.nodePrincipal.addonId == this.id;
}

try {
Expand Down
2 changes: 1 addition & 1 deletion toolkit/components/extensions/ExtensionContent.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ class ContentScriptContextChild extends BaseContext {
// the tab holding the content page.
let metadata = {
"inner-window-id": this.innerWindowID,
addonId: attrs.addonId,
addonId: extensionPrincipal.addonId,
};

this.sandbox = Cu.Sandbox(principal, {
Expand Down
8 changes: 4 additions & 4 deletions toolkit/components/extensions/ExtensionManagement.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ var Service = {
},

// Finds the add-on ID associated with a given moz-extension:// URI.
// This is used to set the addonId on the originAttributes for the
// nsIPrincipal attached to the URI.
// This is used to set the addonId on the for the nsIPrincipal
// attached to the URI.
extensionURIToAddonID(uri) {
let uuid = uri.host;
let extension = this.uuidMap.get(uuid);
Expand All @@ -242,11 +242,11 @@ var Service = {
// API Levels Helpers

// Find the add-on associated with this document via the
// principal's originAttributes. This value is computed by
// principal's addonId attribute. This value is computed by
// extensionURIToAddonID, which ensures that we don't inject our
// API into webAccessibleResources or remote web pages.
function getAddonIdForWindow(window) {
return Cu.getObjectPrincipal(window).originAttributes.addonId;
return Cu.getObjectPrincipal(window).addonId;
}

const API_LEVELS = Object.freeze({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
"use strict";

Cu.import("resource://gre/modules/ExtensionManagement.jsm");
const {Service} = Cu.import("resource://gre/modules/ExtensionManagement.jsm", {});
Cu.import("resource://gre/modules/Services.jsm");

XPCOMUtils.defineLazyServiceGetter(this, "uuidGen",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");

function createWindowWithAddonId(addonId) {
let baseURI = Services.io.newURI("about:blank");
let originAttributes = {addonId};
const uuid = uuidGen.generateUUID().number.slice(1, -1);

const url = `moz-extension://${uuid}/`;

// Set the add-on ID for this moz-extensions: URL.
Service.uuidMap.set(uuid, {id: addonId});
do_register_cleanup(() => {
Service.uuidMap.delete(uuid);
});

let baseURI = Services.io.newURI(url);
let principal = Services.scriptSecurityManager
.createCodebasePrincipal(baseURI, originAttributes);
.createCodebasePrincipal(baseURI, {});
let chromeNav = Services.appShell.createWindowlessBrowser(true);
let interfaceRequestor = chromeNav.QueryInterface(Ci.nsIInterfaceRequestor);
let docShell = interfaceRequestor.getInterface(Ci.nsIDocShell);
Expand All @@ -17,6 +30,8 @@ function createWindowWithAddonId(addonId) {
}

add_task(function* test_eventpages() {
Service.init();

const {getAPILevelForWindow, getAddonIdForWindow} = ExtensionManagement;
const {NO_PRIVILEGES, FULL_PRIVILEGES} = ExtensionManagement.API_LEVELS;
const FAKE_ADDON_ID = "fakeAddonId";
Expand Down

0 comments on commit 9f1b643

Please sign in to comment.