Skip to content

Commit 96ec2c2

Browse files
committed
More precise tracking of implicit origins in tab URLs.
1 parent d7e78ed commit 96ec2c2

1 file changed

Lines changed: 61 additions & 39 deletions

File tree

src/bg/TabGuard.js

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -103,48 +103,70 @@ var TabGuard = (() => {
103103

104104
// we suspect tabs which 1) have not been removed/discarded, 2) are restricted by policy, 3) can run JavaScript
105105
let suspiciousTabs = [...ties].map(TabCache.get).filter(
106-
tab => tab && !tab.discarded && ns.isEnforced(tab.tabId) &&
107-
(tab.url === "about:blank" || ns.policy.can(tab.url, "script")) // TODO: replace about:blank with actual document.domain / window.opener by injecting a content script
106+
tab => tab && !tab.discarded && ns.isEnforced(tab.id) &&
107+
(!(tab._isExplicitOrigin = tab._isExplicitOrigin || /^(?:https?|ftps?|file):/.test(tab.url)) || ns.policy.can(tab.url, "script"))
108108
);
109109

110-
let legitDomains = allowedGroups[tabDomain] || new Set([tabDomain]);
111-
112-
let otherDomains = new Set(suspiciousTabs.map(tab => getDomain(tab.url)).filter(d => d && !legitDomains.has(d)));
113-
if (otherDomains.size === 0) return; // no cross-site ties, no party
114-
115-
if (!requestHeaders.some(h => AUTH_HEADERS_RX.test(h.name))) return; // no auth, no party
116-
117-
// danger zone
118-
119-
let filterAuth = () => {
120-
requestHeaders = requestHeaders.filter(h => !AUTH_HEADERS_RX.test(h.name));
121-
debug("[TabGuard] Removing auth headers from %o (%o)", request, requestHeaders);
122-
return {requestHeaders};
123-
};
124-
125-
let quietDomains = filteredGroups[tabDomain];
126-
if (mainFrame) {
127-
let mustPrompt = (!quietDomains || [...otherDomains].some(d => !quietDomains.has(d)));
128-
if (mustPrompt) {
129-
return (async () => {
130-
let options = [
131-
{label: _("TabGuard_optAnonymize"), checked: true},
132-
{label: _("TabGuard_optAllow")},
133-
];
134-
let ret = await Prompts.prompt({
135-
title: _("TabGuard_title"),
136-
message: _("TabGuard_message", [tabDomain, [...otherDomains].join(", ")]),
137-
options});
138-
if (ret.button !== 0) return {cancel: true};
139-
let list = ret.option === 0 ? filteredGroups : allowedGroups;
140-
otherDomains.add(tabDomain);
141-
for (let d of otherDomains) list[d] = otherDomains;
142-
return list === filteredGroups ? filterAuth() : null;
143-
})();
110+
return suspiciousTabs.length > 0 && (async () => {
111+
112+
let suspiciousDomains = [];
113+
await Promise.all(suspiciousTabs.map(async (tab) => {
114+
if (!tab._isExplicitOrigin) { // e.g. about:blank
115+
// let's try retrieving actual origin
116+
tab._externalUrl = tab.url;
117+
tab._isExplicitOrigin = true;
118+
try {
119+
tab.url = await browser.tabs.executeScript(tab.id, {
120+
runAt: "document_start",
121+
code: "window.origin === 'null' ? window.location.href : window.origin"
122+
});
123+
} catch (e) {
124+
debug(e);
125+
}
126+
debug(`Real origin for ${tab._externalUrl} (tab ${tab.id}) is ${tab.url}.`);
127+
if (!ns.policy.can(tab.url, "script")) return;
128+
}
129+
suspiciousDomains.push(getDomain(tab.url));
130+
}));
131+
132+
let legitDomains = allowedGroups[tabDomain] || new Set([tabDomain]);
133+
let otherDomains = new Set(suspiciousDomains.filter(d => d && !legitDomains.has(d)));
134+
if (otherDomains.size === 0) return; // no cross-site ties, no party
135+
136+
if (!requestHeaders.some(h => AUTH_HEADERS_RX.test(h.name))) return; // no auth, no party
137+
138+
// danger zone
139+
140+
let filterAuth = () => {
141+
requestHeaders = requestHeaders.filter(h => !AUTH_HEADERS_RX.test(h.name));
142+
debug("[TabGuard] Removing auth headers from %o (%o)", request, requestHeaders);
143+
return {requestHeaders};
144+
};
145+
146+
let quietDomains = filteredGroups[tabDomain];
147+
if (mainFrame) {
148+
let mustPrompt = (!quietDomains || [...otherDomains].some(d => !quietDomains.has(d)));
149+
if (mustPrompt) {
150+
return (async () => {
151+
let options = [
152+
{label: _("TabGuard_optAnonymize"), checked: true},
153+
{label: _("TabGuard_optAllow")},
154+
];
155+
let ret = await Prompts.prompt({
156+
title: _("TabGuard_title"),
157+
message: _("TabGuard_message", [tabDomain, [...otherDomains].join(", ")]),
158+
options});
159+
if (ret.button !== 0) return {cancel: true};
160+
let list = ret.option === 0 ? filteredGroups : allowedGroups;
161+
otherDomains.add(tabDomain);
162+
for (let d of otherDomains) list[d] = otherDomains;
163+
return list === filteredGroups ? filterAuth() : null;
164+
})();
165+
}
144166
}
145-
}
146-
let mustFilter = mainFrame || quietDomains && [...otherDomains].some(d => quietDomains.has(d))
147-
return mustFilter ? filterAuth() : null;
167+
let mustFilter = mainFrame || quietDomains && [...otherDomains].some(d => quietDomains.has(d))
168+
return mustFilter ? filterAuth() : null;
169+
})();
148170
},
149171
postCheck(request) {
150172
let {requestId, tabId} = request;

0 commit comments

Comments
 (0)