Bug 1524200 - Sanitizer.jsm should retrieve the list of nsIPrincipal objects with site data only when needed, r=johannh

Differential Revision: https://phabricator.services.mozilla.com/D20995

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2019-02-26 17:27:52 +00:00
parent 130d8fe6b2
commit 53e4ef9c09

View File

@ -664,6 +664,81 @@ async function sanitizeInternal(items, aItemsToClear, progress, options = {}) {
} }
} }
// This is an helper that retrieves the principals with site data just once
// and only when needed.
class PrincipalsCollector {
constructor() {
this.principals = null;
}
async getAllPrincipals(progress) {
if (this.principals == null) {
// Here is the list of principals with site data.
progress.advancement = "get-principals";
this.principals = await this.getAllPrincipalsInternal(progress);
}
return this.principals;
}
async getAllPrincipalsInternal(progress) {
progress.step = "principals-quota-manager";
let principals = await new Promise(resolve => {
quotaManagerService.getUsage(request => {
progress.step = "principals-quota-manager-getUsage";
if (request.resultCode != Cr.NS_OK) {
// We are probably shutting down. We don't want to propagate the
// error, rejecting the promise.
resolve([]);
return;
}
let list = [];
for (let item of request.result) {
let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin);
let uri = principal.URI;
if (isSupportedURI(uri)) {
list.push(principal);
}
}
progress.step = "principals-quota-manager-completed";
resolve(list);
});
}).catch(ex => {
Cu.reportError("QuotaManagerService promise failed: " + ex);
return [];
});
progress.step = "principals-service-workers";
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
for (let i = 0; i < serviceWorkers.length; i++) {
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
// We don't need to check the scheme. SW are just exposed to http/https URLs.
principals.push(sw.principal);
}
// Let's take the list of unique hosts+OA from cookies.
progress.step = "principals-cookies";
let enumerator = Services.cookies.enumerator;
let hosts = new Set();
for (let cookie of enumerator) {
hosts.add(cookie.rawHost + ChromeUtils.originAttributesToSuffix(cookie.originAttributes));
}
progress.step = "principals-host-cookie";
hosts.forEach(host => {
// Cookies and permissions are handled by origin/host. Doesn't matter if we
// use http: or https: schema here.
principals.push(
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin("https://" + host));
});
progress.step = "total-principals:" + principals.length;
return principals;
}
}
async function sanitizeOnShutdown(progress) { async function sanitizeOnShutdown(progress) {
log("Sanitizing on shutdown"); log("Sanitizing on shutdown");
@ -674,9 +749,7 @@ async function sanitizeOnShutdown(progress) {
await Sanitizer.sanitize(itemsToClear, { progress }); await Sanitizer.sanitize(itemsToClear, { progress });
} }
// Here is the list of principals with site data. let principalsCollector = new PrincipalsCollector();
progress.advancement = "get-principals";
let principals = await getAllPrincipals(progress);
// Clear out QuotaManager storage for principals that have been marked as // Clear out QuotaManager storage for principals that have been marked as
// session only. The cookie service has special logic that avoids writing // session only. The cookie service has special logic that avoids writing
@ -704,6 +777,8 @@ async function sanitizeOnShutdown(progress) {
Ci.nsICookieService.ACCEPT_NORMALLY) == Ci.nsICookieService.ACCEPT_SESSION) { Ci.nsICookieService.ACCEPT_NORMALLY) == Ci.nsICookieService.ACCEPT_SESSION) {
log("Session-only configuration detected"); log("Session-only configuration detected");
progress.advancement = "session-only"; progress.advancement = "session-only";
let principals = await principalsCollector.getAllPrincipals(progress);
await maybeSanitizeSessionPrincipals(progress, principals); await maybeSanitizeSessionPrincipals(progress, principals);
return; return;
} }
@ -725,6 +800,7 @@ async function sanitizeOnShutdown(progress) {
log("Custom session cookie permission detected for: " + permission.principal.URI.spec); log("Custom session cookie permission detected for: " + permission.principal.URI.spec);
// We use just the URI here, because permissions ignore OriginAttributes. // We use just the URI here, because permissions ignore OriginAttributes.
let principals = await principalsCollector.getAllPrincipals(progress);
let selectedPrincipals = extractMatchingPrincipals(principals, permission.principal.URI); let selectedPrincipals = extractMatchingPrincipals(principals, permission.principal.URI);
await maybeSanitizeSessionPrincipals(progress, selectedPrincipals); await maybeSanitizeSessionPrincipals(progress, selectedPrincipals);
} }
@ -745,61 +821,6 @@ async function sanitizeOnShutdown(progress) {
progress.advancement = "done"; progress.advancement = "done";
} }
// Retrieve the list of nsIPrincipals with site data.
async function getAllPrincipals(progress) {
progress.step = "principals-quota-manager";
let principals = await new Promise(resolve => {
quotaManagerService.getUsage(request => {
progress.step = "principals-quota-manager-getUsage";
if (request.resultCode != Cr.NS_OK) {
// We are probably shutting down. We don't want to propagate the
// error, rejecting the promise.
resolve([]);
return;
}
let list = [];
for (let item of request.result) {
let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin);
let uri = principal.URI;
if (isSupportedURI(uri)) {
list.push(principal);
}
}
progress.step = "principals-quota-manager-completed";
resolve(list);
});
}).catch(() => []);
progress.step = "principals-service-workers";
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
for (let i = 0; i < serviceWorkers.length; i++) {
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
// We don't need to check the scheme. SW are just exposed to http/https URLs.
principals.push(sw.principal);
}
// Let's take the list of unique hosts+OA from cookies.
progress.step = "principals-cookies";
let enumerator = Services.cookies.enumerator;
let hosts = new Set();
for (let cookie of enumerator) {
hosts.add(cookie.rawHost + ChromeUtils.originAttributesToSuffix(cookie.originAttributes));
}
progress.step = "principals-host-cookie";
hosts.forEach(host => {
// Cookies and permissions are handled by origin/host. Doesn't matter if we
// use http: or https: schema here.
principals.push(
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin("https://" + host));
});
progress.step = "total-principals:" + principals.length;
return principals;
}
// Extracts the principals matching matchUri as root domain. // Extracts the principals matching matchUri as root domain.
function extractMatchingPrincipals(principals, matchUri) { function extractMatchingPrincipals(principals, matchUri) {
return principals.filter(principal => { return principals.filter(principal => {