From 5482e7b53efefce86d7928e11ddd3e6e044d53da Mon Sep 17 00:00:00 2001 From: Michael Layzell Date: Tue, 2 Jun 2015 11:24:42 -0400 Subject: [PATCH] Bug 1173523 - Part 4: Update about:permissions to use new API for nsIPermission, r=margaret --- .../preferences/aboutPermissions.js | 132 +++++++++--------- .../tests/browser_chunk_permissions.js | 16 +-- .../preferences/tests/browser_permissions.js | 14 +- 3 files changed, 82 insertions(+), 80 deletions(-) diff --git a/browser/components/preferences/aboutPermissions.js b/browser/components/preferences/aboutPermissions.js index 50175e4493da..9b0bcce885ad 100644 --- a/browser/components/preferences/aboutPermissions.js +++ b/browser/components/preferences/aboutPermissions.js @@ -17,6 +17,9 @@ Cu.import("resource://gre/modules/ForgetAboutSite.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm"); +let gSecMan = Cc["@mozilla.org/scriptsecuritymanager;1"]. + getService(Ci.nsIScriptSecurityManager); + let gFaviconService = Cc["@mozilla.org/browser/favicon-service;1"]. getService(Ci.nsIFaviconService); @@ -26,7 +29,7 @@ let gPlacesDatabase = Cc["@mozilla.org/browser/nav-history-service;1"]. clone(true); let gSitesStmt = gPlacesDatabase.createAsyncStatement( - "SELECT get_unreversed_host(rev_host) AS host " + + "SELECT url " + "FROM moz_places " + "WHERE rev_host > '.' " + "AND visit_count > 0 " + @@ -46,14 +49,11 @@ let gVisitStmt = gPlacesDatabase.createAsyncStatement( let TEST_EXACT_PERM_TYPES = ["geo", "camera", "microphone"]; /** - * Site object represents a single site, uniquely identified by a host. + * Site object represents a single site, uniquely identified by a principal. */ -function Site(host) { - this.host = host; +function Site(principal) { + this.principal = principal; this.listitem = null; - - this.httpURI = NetUtil.newURI("http://" + this.host); - this.httpsURI = NetUtil.newURI("https://" + this.host); } Site.prototype = { @@ -75,16 +75,10 @@ Site.prototype = { } } - // Try to find favicon for both URIs, but always prefer the https favicon. - gFaviconService.getFaviconURLForPage(this.httpsURI, function (aURI) { + // Get the favicon for the origin + gFaviconService.getFaviconURLForPage(this.principal.URI, function (aURI) { if (aURI) { invokeCallback(aURI); - } else { - gFaviconService.getFaviconURLForPage(this.httpURI, function (aURI) { - if (aURI) { - invokeCallback(aURI); - } - }); } }.bind(this)); }, @@ -96,7 +90,9 @@ Site.prototype = { * A function that takes the visit count (a number) as a parameter. */ getVisitCount: function Site_getVisitCount(aCallback) { - let rev_host = this.host.split("").reverse().join("") + "."; + // XXX This won't be a very reliable system, as it will count both http: and https: visits + // Unfortunately, I don't think that there is a much better way to do it right now. + let rev_host = this.principal.URI.host.split("").reverse().join("") + "."; gVisitStmt.params.rev_host = rev_host; gVisitStmt.executeAsync({ handleResult: function(aResults) { @@ -139,9 +135,9 @@ Site.prototype = { let permissionValue; if (TEST_EXACT_PERM_TYPES.indexOf(aType) == -1) { - permissionValue = Services.perms.testPermission(this.httpURI, aType); + permissionValue = Services.perms.testPermissionFromPrincipal(this.principal, aType); } else { - permissionValue = Services.perms.testExactPermission(this.httpURI, aType); + permissionValue = Services.perms.testExactPermissionFromPrincipal(this.principal, aType); } aResultObj.value = permissionValue; @@ -166,9 +162,7 @@ Site.prototype = { return; } - // Using httpURI is kind of bogus, but the permission manager stores the - // permission for the host, so the right thing happens in the end. - Services.perms.add(this.httpURI, aType, aPerm); + Services.perms.addFromPrincipal(this.principal, aType, aPerm); }, /** @@ -179,7 +173,7 @@ Site.prototype = { * e.g. "cookie", "geo", "indexedDB", "popup", "image" */ clearPermission: function Site_clearPermission(aType) { - Services.perms.remove(this.httpURI, aType); + Services.perms.removeFromPrincipal(this.principal, aType); }, /** @@ -189,13 +183,14 @@ Site.prototype = { * @return An array of the cookies set for the site. */ get cookies() { + let host = this.principal.URI.host; let cookies = []; - let enumerator = Services.cookies.getCookiesFromHost(this.host); + let enumerator = Services.cookies.getCookiesFromHost(host); while (enumerator.hasMoreElements()) { let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); // getCookiesFromHost returns cookies for base domain, but we only want // the cookies for the exact domain. - if (cookie.rawHost == this.host) { + if (cookie.rawHost == host) { cookies.push(cookie); } } @@ -217,27 +212,27 @@ Site.prototype = { * @return An array of the logins stored for the site. */ get logins() { - let httpLogins = Services.logins.findLogins({}, this.httpURI.prePath, "", ""); - let httpsLogins = Services.logins.findLogins({}, this.httpsURI.prePath, "", ""); - return httpLogins.concat(httpsLogins); + let logins = Services.logins.findLogins({}, this.principal.originNoSuffix, "", ""); + return logins; }, get loginSavingEnabled() { - // Only say that login saving is blocked if it is blocked for both http and https. - return Services.logins.getLoginSavingEnabled(this.httpURI.prePath) && - Services.logins.getLoginSavingEnabled(this.httpsURI.prePath); + return Services.logins.getLoginSavingEnabled(this.principal.originNoSuffix); }, set loginSavingEnabled(isEnabled) { - Services.logins.setLoginSavingEnabled(this.httpURI.prePath, isEnabled); - Services.logins.setLoginSavingEnabled(this.httpsURI.prePath, isEnabled); + Services.logins.setLoginSavingEnabled(this.principal.originNoSuffix, isEnabled); }, /** * Removes all data from the browser corresponding to the site. */ forgetSite: function Site_forgetSite() { - ForgetAboutSite.removeDataFromDomain(this.host); + // XXX This removes data for an entire domain, rather than just + // an origin. This may produce confusing results, as data will + // be cleared for the http:// as well as the https:// domain + // if you try to forget the https:// site. + ForgetAboutSite.removeDataFromDomain(this.principal.URI.host); } } @@ -366,7 +361,7 @@ let AboutPermissions = { LIST_BUILD_DELAY: 100, // delay between intervals /** - * Stores a mapping of host strings to Site objects. + * Stores a mapping of origin strings to Site objects. */ _sites: {}, @@ -472,9 +467,9 @@ let AboutPermissions = { break; } let permission = aSubject.QueryInterface(Ci.nsIPermission); - // We can't compare selectedSite.host and permission.host here because - // we need to handle the case where a parent domain was changed in a - // way that affects the subdomain. + // We can't compare selectedSite.principal and permission.principal here + // because we need to handle the case where a parent domain was changed + // in a way that affects the subdomain. if (this._supportedPermissions.indexOf(permission.type) != -1) { this.updatePermission(permission.type); } @@ -512,8 +507,11 @@ let AboutPermissions = { AboutPermissions.startSitesListBatch(); let row; while (row = aResults.getNextRow()) { - let host = row.getResultByName("host"); - AboutPermissions.addHost(host); + let spec = row.getResultByName("url"); + let uri = NetUtil.newURI(spec); + let principal = gSecMan.getNoAppCodebasePrincipal(uri); + + AboutPermissions.addPrincipal(principal); } AboutPermissions.endSitesListBatch(); }, @@ -562,7 +560,8 @@ let AboutPermissions = { try { // aLogin.hostname is a string in origin URL format (e.g. "http://foo.com") let uri = NetUtil.newURI(aLogin.hostname); - this.addHost(uri.host); + let principal = gSecMan.getNoAppCodebasePrincipal(uri); + this.addPrincipal(principal); } catch (e) { // newURI will throw for add-ons logins stored in chrome:// URIs } @@ -577,7 +576,8 @@ let AboutPermissions = { try { // aHostname is a string in origin URL format (e.g. "http://foo.com") let uri = NetUtil.newURI(aHostname); - this.addHost(uri.host); + let principal = gSecMan.getNoAppCodebasePrincipal(uri); + this.addPrincipal(principal); } catch (e) { // newURI will throw for add-ons logins stored in chrome:// URIs } @@ -592,7 +592,7 @@ let AboutPermissions = { let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); // Only include sites with exceptions set for supported permission types. if (this._supportedPermissions.indexOf(permission.type) != -1) { - this.addHost(permission.host); + this.addPrincipal(permission.principal); } itemCnt++; } @@ -603,15 +603,15 @@ let AboutPermissions = { /** * Creates a new Site and adds it to _sites if it's not already there. * - * @param aHost - * A host string. + * @param aPrincipal + * A principal. */ - addHost: function(aHost) { - if (aHost in this._sites) { + addPrincipal: function(aPrincipal) { + if (aPrincipal.origin in this._sites) { return; } - let site = new Site(aHost); - this._sites[aHost] = site; + let site = new Site(aPrincipal); + this._sites[aPrincipal.origin] = site; this.addToSitesList(site); }, @@ -624,7 +624,7 @@ let AboutPermissions = { addToSitesList: function(aSite) { let item = document.createElement("richlistitem"); item.setAttribute("class", "site"); - item.setAttribute("value", aSite.host); + item.setAttribute("value", aSite.principal.origin); aSite.getFavicon(function(aURL) { item.setAttribute("favicon", aURL); @@ -633,7 +633,7 @@ let AboutPermissions = { // Make sure to only display relevant items when list is filtered let filterValue = document.getElementById("sites-filter").value.toLowerCase(); - item.collapsed = aSite.host.toLowerCase().indexOf(filterValue) == -1; + item.collapsed = aSite.principal.origin.toLowerCase().indexOf(filterValue) == -1; (this._listFragment || this.sitesList).appendChild(item); }, @@ -686,16 +686,16 @@ let AboutPermissions = { * The host string corresponding to the site to delete. */ deleteFromSitesList: function(aHost) { - for (let host in this._sites) { - let site = this._sites[host]; - if (site.host.hasRootDomain(aHost)) { + for (let origin in this._sites) { + let site = this._sites[origin]; + if (site.principal.URI.host.hasRootDomain(aHost)) { if (site == this._selectedSite) { // Replace site-specific interface with "All Sites" interface. this.sitesList.selectedItem = document.getElementById("all-sites-item"); } this.sitesList.removeChild(site.listitem); - delete this._sites[site.host]; + delete this._sites[site.principal.origin]; } } }, @@ -711,9 +711,9 @@ let AboutPermissions = { return; } - let host = event.target.value; - let site = this._selectedSite = this._sites[host]; - document.getElementById("site-label").value = host; + let origin = event.target.value; + let site = this._selectedSite = this._sites[origin]; + document.getElementById("site-label").value = origin; document.getElementById("header-deck").selectedPanel = document.getElementById("site-header"); @@ -768,9 +768,9 @@ let AboutPermissions = { // If there is no selected site, we are updating the default permissions interface. permissionValue = PermissionDefaults[aType]; if (aType == "cookie") - // cookie-9 corresponds to ALLOW_FIRST_PARTY_ONLY, which is reserved - // for site-specific preferences only. - document.getElementById("cookie-9").hidden = true; + // cookie-9 corresponds to ALLOW_FIRST_PARTY_ONLY, which is reserved + // for site-specific preferences only. + document.getElementById("cookie-9").hidden = true; } else { if (aType == "cookie") document.getElementById("cookie-9").hidden = false; @@ -825,18 +825,18 @@ let AboutPermissions = { * Opens password manager dialog. */ managePasswords: function() { - let selectedHost = ""; + let selectedOrigin = ""; if (this._selectedSite) { - selectedHost = this._selectedSite.host; + selectedOrigin = this._selectedSite.principal.URI.prePath; } let win = Services.wm.getMostRecentWindow("Toolkit:PasswordManager"); if (win) { - win.setFilter(selectedHost); + win.setFilter(selectedOrigin); win.focus(); } else { window.openDialog("chrome://passwordmgr/content/passwordManager.xul", - "Toolkit:PasswordManager", "", {filterString : selectedHost}); + "Toolkit:PasswordManager", "", {filterString : selectedOrigin}); } }, @@ -877,9 +877,11 @@ let AboutPermissions = { * Opens cookie manager dialog. */ manageCookies: function() { + // Cookies are stored by-host, and thus we filter the cookie window + // using only the host of the selected principal's origin let selectedHost = ""; if (this._selectedSite) { - selectedHost = this._selectedSite.host; + selectedHost = this._selectedSite.principal.URI.host; } let win = Services.wm.getMostRecentWindow("Browser:Cookies"); diff --git a/browser/components/preferences/tests/browser_chunk_permissions.js b/browser/components/preferences/tests/browser_chunk_permissions.js index cf88dd329118..4c53c6c7fe20 100644 --- a/browser/components/preferences/tests/browser_chunk_permissions.js +++ b/browser/components/preferences/tests/browser_chunk_permissions.js @@ -103,11 +103,11 @@ var tests = [ sitesFilter.doCommand(); }, run: function() { - let testSite1 = getSiteItem(TEST_URI_1.host); + let testSite1 = getSiteItem(TEST_URI_1.prePath); ok(testSite1.collapsed, "test site 1 is collapsed after early filtering"); - let testSite2 = getSiteItem(TEST_URI_2.host); + let testSite2 = getSiteItem(TEST_URI_2.prePath); ok(!testSite2.collapsed, "test site 2 is not collapsed after early filtering"); - let testSite3 = getSiteItem(TEST_URI_3.host); + let testSite3 = getSiteItem(TEST_URI_3.prePath); ok(testSite3.collapsed, "test site 3 is collapsed after early filtering"); runNextTest(); @@ -119,11 +119,11 @@ var tests = [ ForgetAboutSite.removeDataFromDomain(TEST_URI_2.host); }, run: function() { - let testSite1 = getSiteItem(TEST_URI_1.host); + let testSite1 = getSiteItem(TEST_URI_1.prePath); ok(testSite1, "test site 1 was not removed from sites list"); - let testSite2 = getSiteItem(TEST_URI_2.host); + let testSite2 = getSiteItem(TEST_URI_2.prePath); ok(!testSite2, "test site 2 was pre-removed from sites list"); - let testSite3 = getSiteItem(TEST_URI_3.host); + let testSite3 = getSiteItem(TEST_URI_3.prePath); ok(testSite3, "test site 3 was not removed from sites list"); runNextTest(); @@ -131,7 +131,7 @@ var tests = [ } ]; -function getSiteItem(aHost) { +function getSiteItem(aPrePath) { return gBrowser.contentDocument. - querySelector(".site[value='" + aHost + "']"); + querySelector(".site[value='" + aPrePath + "']"); } diff --git a/browser/components/preferences/tests/browser_permissions.js b/browser/components/preferences/tests/browser_permissions.js index 2a896b3e0dae..84d91e030247 100644 --- a/browser/components/preferences/tests/browser_permissions.js +++ b/browser/components/preferences/tests/browser_permissions.js @@ -115,8 +115,8 @@ var tests = [ is(gSitesList.firstChild.id, "all-sites-item", "all sites is the first item in the sites list"); - ok(getSiteItem(TEST_URI_1.host), "site item from places db exists"); - ok(getSiteItem(TEST_URI_2.host), "site item from enumerating services exists"); + ok(getSiteItem(TEST_URI_1.prePath), "site item from places db exists"); + ok(getSiteItem(TEST_URI_2.prePath), "site item from enumerating services exists"); runNextTest(); }, @@ -128,9 +128,9 @@ var tests = [ sitesFilter.doCommand(); // make sure correct sites are collapsed/showing - let testSite1 = getSiteItem(TEST_URI_1.host); + let testSite1 = getSiteItem(TEST_URI_1.prePath); ok(!testSite1.collapsed, "test site 1 is not collapsed"); - let testSite2 = getSiteItem(TEST_URI_2.host); + let testSite2 = getSiteItem(TEST_URI_2.prePath); ok(testSite2.collapsed, "test site 2 is collapsed"); // clear filter @@ -202,13 +202,13 @@ var tests = [ function test_select_site() { // select the site that has the permissions we set at the beginning of the test - let testSiteItem = getSiteItem(TEST_URI_2.host); + let testSiteItem = getSiteItem(TEST_URI_2.prePath); gSitesList.selectedItem = testSiteItem; let siteHeader = gBrowser.contentDocument.getElementById("site-header"); is(siteHeader, gHeaderDeck.selectedPanel, "correct header shown for a specific site"); - is(gSiteLabel.value, TEST_URI_2.host, "header updated for selected site"); + is(gSiteLabel.value, TEST_URI_2.prePath, "header updated for selected site"); ok(!gBrowser.contentDocument.getElementById("passwords-count").hidden, "passwords count is not hidden"); @@ -283,7 +283,7 @@ var tests = [ "all sites item selected after forgetting selected site"); // check to make sure site is gone from sites list - let testSiteItem = getSiteItem(TEST_URI_2.host); + let testSiteItem = getSiteItem(TEST_URI_2.prePath); ok(!testSiteItem, "site removed from sites list"); // check to make sure we forgot all permissions corresponding to site