aboutsummaryrefslogtreecommitdiffstats
path: root/js/traffic.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/traffic.js')
-rw-r--r--js/traffic.js484
1 files changed, 243 insertions, 241 deletions
diff --git a/js/traffic.js b/js/traffic.js
index 0c71f85..aae4070 100644
--- a/js/traffic.js
+++ b/js/traffic.js
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://notabug.org/heckyel/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -31,255 +31,257 @@
// Intercept and filter web requests according to white and black lists.
var onBeforeRootFrameRequestHandler = function (details) {
- let ηm = ηMatrix;
- let requestURL = details.url;
- let requestHostname = UriTools.hostnameFromURI(requestURL);
- let tabId = details.tabId;
+ let ηm = ηMatrix;
+ let requestURL = details.url;
+ let requestHostname = UriTools.hostnameFromURI(requestURL);
+ let tabId = details.tabId;
- ηm.tabContextManager.push(tabId, requestURL);
+ ηm.tabContextManager.push(tabId, requestURL);
- let tabContext = ηm.tabContextManager.mustLookup(tabId);
- let rootHostname = tabContext.rootHostname;
+ let tabContext = ηm.tabContextManager.mustLookup(tabId);
+ let rootHostname = tabContext.rootHostname;
- // Disallow request as per matrix?
- let block = ηm.mustBlock(rootHostname, requestHostname, 'doc');
+ // Disallow request as per matrix?
+ let block = ηm.mustBlock(rootHostname, requestHostname, 'doc');
- let pageStore = ηm.pageStoreFromTabId(tabId);
- pageStore.recordRequest('doc', requestURL, block);
- ηm.logger.writeOne(tabId, 'net', rootHostname, requestURL, 'doc', block);
+ let pageStore = ηm.pageStoreFromTabId(tabId);
+ pageStore.recordRequest('doc', requestURL, block);
+ ηm.logger.writeOne(tabId, 'net', rootHostname, requestURL, 'doc', block);
- // Not blocked
- if (!block) {
+ // Not blocked
+ if (!block) {
// rhill 2013-11-07: Senseless to do this for
// behind-the-scene requests.
ηm.cookieHunter.recordPageCookies(pageStore);
return;
- }
+ }
- // Blocked
- var query = btoa(JSON.stringify({
+ // Blocked
+ var query = btoa(JSON.stringify({
url: requestURL,
hn: requestHostname,
why: '?'
- }));
+ }));
- vAPI.tabs.replace(tabId,
- vAPI.getURL('main-blocked.html?details=') + query);
+ vAPI.tabs.replace(tabId,
+ vAPI.getURL('main-blocked.html?details=') + query);
- return {
- cancel: true
- };
+ return {
+ cancel: true
+ };
};
// Intercept and filter web requests according to white and black lists.
var onBeforeRequestHandler = function (details) {
- let ηm = ηMatrix;
+ let ηm = ηMatrix;
let requestURL = details.url;
let requestScheme = UriTools.schemeFromURI(requestURL);
- if (UriTools.isNetworkScheme(requestScheme) === false) {
- return;
- }
+ if (UriTools.isNetworkScheme(requestScheme) === false) {
+ return;
+ }
- var requestType = requestTypeNormalizer[details.type] || 'other';
+ var requestType = requestTypeNormalizer[details.type] || 'other';
- // https://github.com/gorhill/httpswitchboard/issues/303
- // Wherever the main doc comes from, create a receiver page
- // URL: synthetize one if needed.
- if (requestType === 'doc' && details.parentFrameId === -1) {
+ // https://github.com/gorhill/httpswitchboard/issues/303
+ // Wherever the main doc comes from, create a receiver page
+ // URL: synthetize one if needed.
+ if (requestType === 'doc' && details.parentFrameId === -1) {
return onBeforeRootFrameRequestHandler(details);
- }
-
- // Re-classify orphan HTTP requests as behind-the-scene
- // requests. There is not much else which can be done, because
- // there are URLs which cannot be handled by ηMatrix,
- // i.e. `opera://startpage`, as this would lead to
- // complications with no obvious solution, like how to scope
- // on unknown scheme? Etc.
- // https://github.com/gorhill/httpswitchboard/issues/191
- // https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
- let tabContext = ηm.tabContextManager.mustLookup(details.tabId);
+ }
+
+ // Re-classify orphan HTTP requests as behind-the-scene
+ // requests. There is not much else which can be done, because
+ // there are URLs which cannot be handled by ηMatrix,
+ // i.e. `opera://startpage`, as this would lead to
+ // complications with no obvious solution, like how to scope
+ // on unknown scheme? Etc.
+ // https://github.com/gorhill/httpswitchboard/issues/191
+ // https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
+ let tabContext = ηm.tabContextManager.mustLookup(details.tabId);
let tabId = tabContext.tabId;
let rootHostname = tabContext.rootHostname;
let specificity = 0;
- // Filter through matrix
- let block = ηm.tMatrix.mustBlock(rootHostname,
- UriTools.hostnameFromURI(requestURL),
- requestType);
- if (block) {
+ // Filter through matrix
+ let block = ηm.tMatrix.mustBlock(rootHostname,
+ UriTools.hostnameFromURI(requestURL),
+ requestType);
+ if (block) {
specificity = ηm.tMatrix.specificityRegister;
- }
-
- // Record request.
- // https://github.com/gorhill/httpswitchboard/issues/342
- // The way requests are handled now, it may happen at this
- // point some processing has already been performed, and that
- // a synthetic URL has been constructed for logging
- // purpose. Use this synthetic URL if it is available.
- let pageStore = ηm.mustPageStoreFromTabId(tabId);
-
- // Enforce strict secure connection?
- if (tabContext.secure
- && UriTools.isSecureScheme(requestScheme) === false) {
+ }
+
+ // Record request.
+ // https://github.com/gorhill/httpswitchboard/issues/342
+ // The way requests are handled now, it may happen at this
+ // point some processing has already been performed, and that
+ // a synthetic URL has been constructed for logging
+ // purpose. Use this synthetic URL if it is available.
+ let pageStore = ηm.mustPageStoreFromTabId(tabId);
+
+ // Enforce strict secure connection?
+ if (tabContext.secure
+ && UriTools.isSecureScheme(requestScheme) === false) {
pageStore.hasMixedContent = true;
if (block === false) {
- block = ηm.tMatrix.evaluateSwitchZ('https-strict', rootHostname);
+ block = ηm.tMatrix.evaluateSwitchZ('https-strict', rootHostname);
}
- }
+ }
- pageStore.recordRequest(requestType, requestURL, block);
- ηm.logger.writeOne(tabId, 'net', rootHostname,
- requestURL, details.type, block);
+ pageStore.recordRequest(requestType, requestURL, block);
+ ηm.logger.writeOne(tabId, 'net', rootHostname,
+ requestURL, details.type, block);
- if (block) {
+ if (block) {
pageStore.cacheBlockedCollapsible(requestType,
- requestURL, specificity);
+ requestURL, specificity);
return {
- 'cancel': true
- };
- }
+ 'cancel': true
+ };
+ }
};
// Sanitize outgoing headers as per user settings.
var onBeforeSendHeadersHandler = function (details) {
- let ηm = ηMatrix;
+ let ηm = ηMatrix;
let requestURL = details.url;
let requestScheme = UriTools.schemeFromURI(requestURL);
- // Ignore non-network schemes
- if (UriTools.isNetworkScheme(requestScheme) === false) {
- return;
- }
-
- // Re-classify orphan HTTP requests as behind-the-scene
- // requests. There is not much else which can be done, because
- // there are URLs which cannot be handled by HTTP Switchboard,
- // i.e. `opera://startpage`, as this would lead to
- // complications with no obvious solution, like how to scope
- // on unknown scheme? Etc.
- // https://github.com/gorhill/httpswitchboard/issues/191
- // https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
- let tabId = details.tabId;
+ // Ignore non-network schemes
+ if (UriTools.isNetworkScheme(requestScheme) === false) {
+ return;
+ }
+
+ // Re-classify orphan HTTP requests as behind-the-scene
+ // requests. There is not much else which can be done, because
+ // there are URLs which cannot be handled by HTTP Switchboard,
+ // i.e. `opera://startpage`, as this would lead to
+ // complications with no obvious solution, like how to scope
+ // on unknown scheme? Etc.
+ // https://github.com/gorhill/httpswitchboard/issues/191
+ // https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
+ let tabId = details.tabId;
let pageStore = ηm.mustPageStoreFromTabId(tabId);
let requestType = requestTypeNormalizer[details.type] || 'other';
let requestHeaders = details.requestHeaders;
let headerIndex, headerValue;
- // https://github.com/gorhill/httpswitchboard/issues/342
- // Is this hyperlink auditing? If yes, create a synthetic URL
- // for reporting hyperlink auditing in request log. This way
- // the user is better informed of what went on.
-
- // https://html.spec.whatwg.org/multipage/links.html#hyperlink-auditing
- //
- // Target URL = the href of the link
- // Doc URL = URL of the document containing the target URL
- // Ping URLs = servers which will be told that user clicked target URL
- //
- // `Content-Type` = `text/ping` (always present)
- // `Ping-To` = target URL (always present)
- // `Ping-From` = doc URL
- // `Referer` = doc URL
- // request URL = URL which will receive the information
- //
- // With hyperlink-auditing, removing header(s) is pointless, the whole
- // request must be cancelled.
- headerIndex = headerIndexFromName('ping-to', requestHeaders);
- if (headerIndex !== -1) {
+ // https://github.com/gorhill/httpswitchboard/issues/342
+ // Is this hyperlink auditing? If yes, create a synthetic URL
+ // for reporting hyperlink auditing in request log. This way
+ // the user is better informed of what went on.
+
+ // https://html.spec.whatwg.org/multipage/links.html#hyperlink-auditing
+ //
+ // Target URL = the href of the link
+ // Doc URL = URL of the document containing the target URL
+ // Ping URLs = servers which will be told that user clicked target URL
+ //
+ // `Content-Type` = `text/ping` (always present)
+ // `Ping-To` = target URL (always present)
+ // `Ping-From` = doc URL
+ // `Referer` = doc URL
+ // request URL = URL which will receive the information
+ //
+ // With hyperlink-auditing, removing header(s) is pointless, the whole
+ // request must be cancelled.
+ headerIndex = headerIndexFromName('ping-to', requestHeaders);
+ if (headerIndex !== -1) {
headerValue = requestHeaders[headerIndex].value;
if (headerValue !== '') {
- let block = ηm.userSettings.processHyperlinkAuditing;
- pageStore.recordRequest('other',
- requestURL
- + '{Ping-To:'
- + headerValue
- + '}', block);
- ηm.logger.writeOne(tabId, 'net', '', requestURL, 'ping', block);
- if (block) {
+ let block = ηm.userSettings.processHyperlinkAuditing;
+ pageStore.recordRequest('other',
+ requestURL
+ + '{Ping-To:'
+ + headerValue
+ + '}', block);
+ ηm.logger.writeOne(tabId, 'net', '', requestURL, 'ping', block);
+ if (block) {
ηm.hyperlinkAuditingFoiledCounter += 1;
return {
- 'cancel': true
- };
- }
+ 'cancel': true
+ };
+ }
}
- }
+ }
- // If we reach this point, request is not blocked, so what is
- // left to do is to sanitize headers.
- let rootHostname = pageStore.pageHostname;
+ // If we reach this point, request is not blocked, so what is
+ // left to do is to sanitize headers.
+ let rootHostname = pageStore.pageHostname;
let requestHostname = UriTools.hostnameFromURI(requestURL);
let modified = false;
- // Process `Cookie` header.
- headerIndex = headerIndexFromName('cookie', requestHeaders);
- if (headerIndex !== -1
- && ηm.mustBlock(rootHostname, requestHostname, 'cookie')) {
+ // Process `Cookie` header.
+ headerIndex = headerIndexFromName('cookie', requestHeaders);
+ if (headerIndex !== -1
+ && ηm.mustBlock(rootHostname, requestHostname, 'cookie')) {
modified = true;
headerValue = requestHeaders[headerIndex].value;
requestHeaders.splice(headerIndex, 1);
ηm.cookieHeaderFoiledCounter++;
if (requestType === 'doc') {
- ηm.logger.writeOne(tabId, 'net', '', headerValue, 'COOKIE', true);
+ pageStore.perLoadBlockedRequestCount++;
+ ηm.logger.writeOne(tabId, 'net', '', headerValue, 'COOKIE', true);
}
- }
+ }
- // Process `Referer` header.
- // https://github.com/gorhill/httpswitchboard/issues/222#issuecomment-44828402
+ // Process `Referer` header.
+ // https://github.com/gorhill/httpswitchboard/issues/222#issuecomment-44828402
- // https://github.com/gorhill/uMatrix/issues/320
- // http://tools.ietf.org/html/rfc6454#section-7.3
- // "The user agent MAY include an Origin header field in any HTTP
- // "request.
- // "The user agent MUST NOT include more than one Origin header field in
- // "any HTTP request.
- // "Whenever a user agent issues an HTTP request from a "privacy-
- // "sensitive" context, the user agent MUST send the value "null" in the
- // "Origin header field."
+ // https://github.com/gorhill/uMatrix/issues/320
+ // http://tools.ietf.org/html/rfc6454#section-7.3
+ // "The user agent MAY include an Origin header field in any HTTP
+ // "request.
+ // "The user agent MUST NOT include more than one Origin header field in
+ // "any HTTP request.
+ // "Whenever a user agent issues an HTTP request from a "privacy-
+ // "sensitive" context, the user agent MUST send the value "null" in the
+ // "Origin header field."
- // https://github.com/gorhill/uMatrix/issues/358
- // Do not spoof `Origin` header for the time being.
+ // https://github.com/gorhill/uMatrix/issues/358
+ // Do not spoof `Origin` header for the time being.
- // https://github.com/gorhill/uMatrix/issues/773
- // For non-GET requests, remove `Referer` header instead of spoofing it.
+ // https://github.com/gorhill/uMatrix/issues/773
+ // For non-GET requests, remove `Referer` header instead of spoofing it.
- headerIndex = headerIndexFromName('referer', requestHeaders);
- if (headerIndex !== -1) {
+ headerIndex = headerIndexFromName('referer', requestHeaders);
+ if (headerIndex !== -1) {
headerValue = requestHeaders[headerIndex].value;
if (headerValue !== '') {
- let toDomain = UriTools.domainFromHostname(requestHostname);
- if (toDomain !== ''
- && toDomain !== UriTools.domainFromURI(headerValue)) {
+ let toDomain = UriTools.domainFromHostname(requestHostname);
+ if (toDomain !== ''
+ && toDomain !== UriTools.domainFromURI(headerValue)) {
pageStore.has3pReferrer = true;
if (ηm.tMatrix.evaluateSwitchZ('referrer-spoof',
- rootHostname)) {
- modified = true;
- let newValue;
- if (details.method === 'GET') {
+ rootHostname)) {
+ modified = true;
+ let newValue;
+ if (details.method === 'GET') {
newValue = requestHeaders[headerIndex].value =
- requestScheme + '://' + requestHostname + '/';
- } else {
+ requestScheme + '://' + requestHostname + '/';
+ } else {
requestHeaders.splice(headerIndex, 1);
- }
- ηm.refererHeaderFoiledCounter++;
- if (requestType === 'doc') {
+ }
+ ηm.refererHeaderFoiledCounter++;
+ if (requestType === 'doc') {
+ pageStore.perLoadBlockedRequestCount++;
ηm.logger.writeOne(tabId, 'net', '',
- headerValue, 'REFERER', true);
+ headerValue, 'REFERER', true);
if (newValue !== undefined) {
- ηm.logger.writeOne(tabId, 'net', '',
- newValue, 'REFERER', false);
+ ηm.logger.writeOne(tabId, 'net', '',
+ newValue, 'REFERER', false);
}
- }
+ }
}
- }
+ }
}
- }
+ }
- if (modified) {
+ if (modified) {
return {
- requestHeaders: requestHeaders
- };
- }
+ requestHeaders: requestHeaders
+ };
+ }
};
// To prevent inline javascript from being executed.
@@ -290,144 +292,144 @@
// This fixes:
// https://github.com/gorhill/httpswitchboard/issues/35
var onHeadersReceived = function (details) {
- // Ignore schemes other than 'http...'
- let ηm = ηMatrix;
+ // Ignore schemes other than 'http...'
+ let ηm = ηMatrix;
let tabId = details.tabId;
let requestURL = details.url;
let requestType = requestTypeNormalizer[details.type] || 'other';
- // https://github.com/gorhill/uMatrix/issues/145
- // Check if the main_frame is a download
- if (requestType === 'doc') {
+ // https://github.com/gorhill/uMatrix/issues/145
+ // Check if the main_frame is a download
+ if (requestType === 'doc') {
ηm.tabContextManager.push(tabId, requestURL);
- }
+ }
- let tabContext = ηm.tabContextManager.lookup(tabId);
- if (tabContext === null) {
- return;
- }
+ let tabContext = ηm.tabContextManager.lookup(tabId);
+ if (tabContext === null) {
+ return;
+ }
- let csp = [];
+ let csp = [];
let cspReport = [];
let rootHostname = tabContext.rootHostname;
let requestHostname = UriTools.hostnameFromURI(requestURL);
- // Inline script tags.
- if (ηm.mustAllow(rootHostname, requestHostname, 'script') !== true) {
+ // Inline script tags.
+ if (ηm.mustAllow(rootHostname, requestHostname, 'script') !== true) {
csp.push(ηm.cspNoInlineScript);
- }
+ }
- // Inline style tags.
- if (ηm.mustAllow(rootHostname, requestHostname, 'css') !== true) {
+ // Inline style tags.
+ if (ηm.mustAllow(rootHostname, requestHostname, 'css') !== true) {
csp.push(ηm.cspNoInlineStyle);
- }
+ }
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1302667
- let cspNoWorker = ηm.cspNoWorker;
- if (cspNoWorker === undefined) {
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1302667
+ let cspNoWorker = ηm.cspNoWorker;
+ if (cspNoWorker === undefined) {
cspNoWorker = cspNoWorkerInit();
- }
+ }
- if (ηm.tMatrix.evaluateSwitchZ('no-workers', rootHostname)) {
+ if (ηm.tMatrix.evaluateSwitchZ('no-workers', rootHostname)) {
csp.push(cspNoWorker);
- } else if (ηm.rawSettings.disableCSPReportInjection === false) {
+ } else if (ηm.rawSettings.disableCSPReportInjection === false) {
cspReport.push(cspNoWorker);
- }
+ }
- let headers = details.responseHeaders;
+ let headers = details.responseHeaders;
let cspDirectives, i;
- if (csp.length !== 0) {
+ if (csp.length !== 0) {
cspDirectives = csp.join(',');
i = headerIndexFromName('content-security-policy', headers);
if (i !== -1) {
- headers[i].value += ',' + cspDirectives;
+ headers[i].value += ',' + cspDirectives;
} else {
- headers.push({
+ headers.push({
name: 'Content-Security-Policy',
value: cspDirectives
- });
+ });
}
if (requestType === 'doc') {
- ηm.logger.writeOne(tabId, 'net', '', cspDirectives, 'CSP', false);
+ ηm.logger.writeOne(tabId, 'net', '', cspDirectives, 'CSP', false);
}
- }
+ }
- if (cspReport.length !== 0) {
+ if (cspReport.length !== 0) {
cspDirectives = cspReport.join(',');
i = headerIndexFromName('content-security-policy-report-only',
- headers);
+ headers);
if (i !== -1) {
- headers[i].value += ',' + cspDirectives;
+ headers[i].value += ',' + cspDirectives;
} else {
- headers.push({
+ headers.push({
name: 'Content-Security-Policy-Report-Only',
value: cspDirectives
- });
+ });
}
- }
+ }
- return {
- responseHeaders: headers
- };
+ return {
+ responseHeaders: headers
+ };
};
let cspNoWorkerInit = function () {
- if (ηMatrix.cspNoWorker === undefined) {
- ηMatrix.cspNoWorker = "worker-src 'none'; "
- +"frame-src data: blob: *; "
- +"report-uri about:blank";
- }
+ if (ηMatrix.cspNoWorker === undefined) {
+ ηMatrix.cspNoWorker = "worker-src 'none'; "
+ +"frame-src data: blob: *; "
+ +"report-uri about:blank";
+ }
- return ηMatrix.cspNoWorker;
+ return ηMatrix.cspNoWorker;
};
// Caller must ensure headerName is normalized to lower case.
let headerIndexFromName = function (headerName, headers) {
- for (let i=0; i<headers.length; ++i) {
+ for (let i=0; i<headers.length; ++i) {
if ( headers[i].name.toLowerCase() === headerName ) {
- return i;
+ return i;
}
- }
+ }
- return -1;
+ return -1;
};
let requestTypeNormalizer = {
- 'font' : 'css',
- 'image' : 'image',
- 'imageset' : 'image',
- 'main_frame' : 'doc',
- 'media' : 'media',
- 'object' : 'media',
- 'other' : 'other',
- 'script' : 'script',
- 'stylesheet' : 'css',
- 'sub_frame' : 'frame',
- 'websocket' : 'xhr',
- 'xmlhttprequest': 'xhr'
+ 'font' : 'css',
+ 'image' : 'image',
+ 'imageset' : 'image',
+ 'main_frame' : 'doc',
+ 'media' : 'media',
+ 'object' : 'media',
+ 'other' : 'other',
+ 'script' : 'script',
+ 'stylesheet' : 'css',
+ 'sub_frame' : 'frame',
+ 'websocket' : 'xhr',
+ 'xmlhttprequest': 'xhr'
};
vAPI.net.onBeforeRequest = {
- extra: [ 'blocking' ],
- callback: onBeforeRequestHandler
+ extra: [ 'blocking' ],
+ callback: onBeforeRequestHandler
};
vAPI.net.onBeforeSendHeaders = {
- extra: [ 'blocking', 'requestHeaders' ],
- callback: onBeforeSendHeadersHandler
+ extra: [ 'blocking', 'requestHeaders' ],
+ callback: onBeforeSendHeadersHandler
};
vAPI.net.onHeadersReceived = {
- urls: [ 'http://*/*', 'https://*/*' ],
- types: [ 'main_frame', 'sub_frame' ],
- extra: [ 'blocking', 'responseHeaders' ],
- callback: onHeadersReceived
+ urls: [ 'http://*/*', 'https://*/*' ],
+ types: [ 'main_frame', 'sub_frame' ],
+ extra: [ 'blocking', 'responseHeaders' ],
+ callback: onHeadersReceived
};
return {
- start: function () {
- vAPI.net.registerListeners();
- },
+ start: function () {
+ vAPI.net.registerListeners();
+ },
};
})();