@@ -32,8 +32,16 @@ var TabGuard = (() => {
3232 const AUTH_HEADERS_RX = / ^ (?: a u t h o r i z a t i o n | c o o k i e ) / 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" && / ^ (?: s a m e - (?: s i t e | o r i g i n ) | n o n e ) $ / 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
0 commit comments