Skip to content

Commit e2a235a

Browse files
committed
[TabGuard] Improved specificity + some bug fixes (thanks barbaz and fatboy).
1 parent ce5bf8c commit e2a235a

2 files changed

Lines changed: 36 additions & 10 deletions

File tree

src/bg/TabGuard.js

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,16 @@ var TabGuard = (() => {
3232
const AUTH_HEADERS_RX = /^(?:authorization|cookie)/i;
3333

3434
function getDomain(u) {
35-
let {url} = Sites.parse(u);
36-
return url && url.protocol.startsWith("http") && tld.getDomain(url.hostname);
35+
let {url, siteKey} = Sites.parse(u);
36+
return url && url.protocol.startsWith("http") && tld.getDomain(url.hostname) || Sites.origin(siteKey);
37+
}
38+
39+
function flattenHeaders(headers) {
40+
let flat = {};
41+
for (let h of headers) {
42+
flat[h.name.toLowerCase()] = h.value;
43+
}
44+
return flat;
3745
}
3846

3947
return {
@@ -42,34 +50,52 @@ var TabGuard = (() => {
4250
const mode = ns.sync.TabGuardMode;
4351
if (mode === "off" || !request.incognito && mode!== "global") return;
4452

45-
const {tabId, type, url} = request;
53+
const {tabId, type, url, originUrl} = request;
4654

4755
if (tabId < 0) return; // no tab, no party
4856

57+
if (!ns.isEnforced(tabId)) return; // leave unrestricted tabs alone
58+
59+
let {requestHeaders} = request;
60+
61+
const mainFrame = type === "main_frame";
62+
if (mainFrame) {
63+
let headers = flattenHeaders(requestHeaders);
64+
if (headers["sec-fetch-user"] === "?1" && /^(?:same-(?:site|origin)|none)$/i.test(headers["sec-fetch-site"])) {
65+
debug("[TabGuard] User-typed, bookmark, reload or user-activated same-site navigation: cutting tab ties.", request);
66+
TabTies.cut(tabId);
67+
return;
68+
}
69+
}
70+
4971
let targetDomain = getDomain(url);
5072
if (!targetDomain) return; // no domain, no cookies
5173

52-
const mainFrame = type === "main_frame";
53-
let tabDomain = getDomain(mainFrame ? url : TabCache.get(tabId).url);
74+
let tab = TabCache.get(tabId);
75+
let tabDomain = getDomain(mainFrame ? url : tab && tab.url);
5476
if (!tabDomain) return; // no domain, no cookies
5577

5678
let ties = TabTies.get(tabId);
5779
if (ties.size === 0) return; // no ties, no party
5880

81+
// we suspect tabs which 1) have not been removed/discarded, 2) are restricted by policy, 3) can run JavaScript
82+
let suspiciousTabs = [...ties].map(TabCache.get).filter(
83+
tab => tab && !tab.discarded && ns.isEnforced(tab.tabId) &&
84+
(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
85+
);
86+
5987
let legitDomains = allowedGroups[tabDomain] || new Set([tabDomain]);
6088

61-
let otherDomains = new Set([...ties].map(id => getDomain(TabCache.get(id).url)).filter(d => !legitDomains.has(d)));
89+
let otherDomains = new Set(suspiciousTabs.map(tab => getDomain(tab.url)).filter(d => d && !legitDomains.has(d)));
6290
if (otherDomains.size === 0) return; // no cross-site ties, no party
6391

64-
let {requestHeaders} = request;
65-
6692
if (!requestHeaders.some(h => AUTH_HEADERS_RX.test(h.name))) return; // no auth, no party
6793

6894
// danger zone
6995

7096
let filterAuth = () => {
7197
requestHeaders = requestHeaders.filter(h => !AUTH_HEADERS_RX.test(h.name));
72-
debug("TabGuard removing auth headers from %o (%o)", request, requestHeaders);
98+
debug("[TabGuard] Removing auth headers from %o (%o)", request, requestHeaders);
7399
return {requestHeaders};
74100
};
75101

src/nscl

0 commit comments

Comments
 (0)