Browse Source

extremely early draft of matrix integration within the logger

pull/2/head
gorhill 10 years ago
parent
commit
6f786635f4
  1. 82
      platform/chromium/vapi-background.js
  2. 52
      platform/firefox/vapi-background.js
  3. 146
      src/css/logger-ui.css
  4. 2
      src/js/background.js
  5. 22
      src/js/contentscript-end.js
  6. 14
      src/js/cookies.js
  7. 12
      src/js/httpsb.js
  8. 260
      src/js/logger-ui.js
  9. 29
      src/js/messaging.js
  10. 2
      src/js/pagestats.js
  11. 12
      src/js/popup.js
  12. 5
      src/js/storage.js
  13. 6
      src/js/tab.js
  14. 21
      src/js/traffic.js
  15. 5
      src/js/useragent.js
  16. 24
      src/logger-ui.html

82
platform/chromium/vapi-background.js

@ -103,7 +103,6 @@ vAPI.noTabId = '-1';
vAPI.tabs.registerListeners = function() { vAPI.tabs.registerListeners = function() {
var onNavigationClient = this.onNavigation || noopFunc; var onNavigationClient = this.onNavigation || noopFunc;
var onPopupClient = this.onPopup || noopFunc;
var onUpdatedClient = this.onUpdated || noopFunc; var onUpdatedClient = this.onUpdated || noopFunc;
var onClosedClient = this.onClosed || noopFunc; var onClosedClient = this.onClosed || noopFunc;
@ -114,59 +113,6 @@ vAPI.tabs.registerListeners = function() {
// onDOMContentLoaded -> // onDOMContentLoaded ->
// onCompleted // onCompleted
var popupCandidates = Object.create(null);
var PopupCandidate = function(details) {
this.targetTabId = details.tabId;
this.openerTabId = details.sourceTabId;
this.targetURL = details.url;
this.selfDestructionTimer = null;
};
PopupCandidate.prototype.selfDestruct = function() {
if ( this.selfDestructionTimer !== null ) {
clearTimeout(this.selfDestructionTimer);
}
delete popupCandidates[this.targetTabId];
};
PopupCandidate.prototype.launchSelfDestruction = function() {
if ( this.selfDestructionTimer !== null ) {
clearTimeout(this.selfDestructionTimer);
}
this.selfDestructionTimer = setTimeout(this.selfDestruct.bind(this), 10000);
};
var popupCandidateCreate = function(details) {
var popup = popupCandidates[details.tabId];
// This really should not happen...
if ( popup !== undefined ) {
return;
}
popup = popupCandidates[details.tabId] = new PopupCandidate(details);
return popup;
};
var popupCandidateTest = function(details) {
var popup = popupCandidates[details.tabId];
if ( popup === undefined ) {
return;
}
popup.targetURL = details.url;
if ( onPopupClient(popup) !== true ) {
return;
}
popup.selfDestruct();
return true;
};
var popupCandidateDestroy = function(details) {
var popup = popupCandidates[details.tabId];
if ( popup instanceof PopupCandidate ) {
popup.launchSelfDestruction();
}
};
// The chrome.webRequest.onBeforeRequest() won't be called for everything // The chrome.webRequest.onBeforeRequest() won't be called for everything
// else than `http`/`https`. Thus, in such case, we will bind the tab as // else than `http`/`https`. Thus, in such case, we will bind the tab as
// early as possible in order to increase the likelihood of a context // early as possible in order to increase the likelihood of a context
@ -176,30 +122,17 @@ vAPI.tabs.registerListeners = function() {
var reGoodForWebRequestAPI = /^https?:\/\//; var reGoodForWebRequestAPI = /^https?:\/\//;
var onCreatedNavigationTarget = function(details) { var onCreatedNavigationTarget = function(details) {
details.tabId = details.tabId.toString();
//console.debug('onCreatedNavigationTarget: popup candidate tab id %d = "%s"', details.tabId, details.url);
if ( reGoodForWebRequestAPI.test(details.url) === false ) {
details.frameId = 0;
onNavigationClient(details);
}
popupCandidateCreate(details);
popupCandidateTest(details);
};
var onBeforeNavigate = function(details) {
if ( details.frameId !== 0 ) {
//console.debug('onCreatedNavigationTarget: tab id %d = "%s"', details.tabId, details.url);
if ( reGoodForWebRequestAPI.test(details.url) ) {
return; return;
} }
//console.debug('onBeforeNavigate: popup candidate tab id %d = "%s"', details.tabId, details.url);
details.tabId = details.tabId.toString(); details.tabId = details.tabId.toString();
popupCandidateTest(details);
details.frameId = 0;
onNavigationClient(details);
}; };
var onUpdated = function(tabId, changeInfo, tab) { var onUpdated = function(tabId, changeInfo, tab) {
tabId = tabId.toString(); tabId = tabId.toString();
if ( changeInfo.url && popupCandidateTest({ tabId: tabId, url: changeInfo.url }) ) {
return;
}
onUpdatedClient(tabId, changeInfo, tab); onUpdatedClient(tabId, changeInfo, tab);
}; };
@ -209,11 +142,7 @@ vAPI.tabs.registerListeners = function() {
} }
details.tabId = details.tabId.toString(); details.tabId = details.tabId.toString();
onNavigationClient(details); onNavigationClient(details);
//console.debug('onCommitted: popup candidate tab id %d = "%s"', details.tabId, details.url);
if ( popupCandidateTest(details) === true ) {
return;
}
popupCandidateDestroy(details);
//console.debug('onCommitted: tab id %d = "%s"', details.tabId, details.url);
}; };
var onClosed = function(tabId) { var onClosed = function(tabId) {
@ -221,7 +150,6 @@ vAPI.tabs.registerListeners = function() {
}; };
chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTarget); chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTarget);
chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigate);
chrome.webNavigation.onCommitted.addListener(onCommitted); chrome.webNavigation.onCommitted.addListener(onCommitted);
chrome.tabs.onUpdated.addListener(onUpdated); chrome.tabs.onUpdated.addListener(onUpdated);
chrome.tabs.onRemoved.addListener(onClosed); chrome.tabs.onRemoved.addListener(onClosed);

52
platform/firefox/vapi-background.js

@ -390,7 +390,6 @@ vAPI.tabs = {};
vAPI.tabs.registerListeners = function() { vAPI.tabs.registerListeners = function() {
// onClosed - handled in tabWatcher.onTabClose // onClosed - handled in tabWatcher.onTabClose
// onPopup - handled in httpObserver.handlePopup
for ( var win of this.getWindows() ) { for ( var win of this.getWindows() ) {
windowWatcher.onReady.call(win); windowWatcher.onReady.call(win);
@ -1101,24 +1100,6 @@ var httpObserver = {
); );
}, },
handlePopup: function(URI, tabId, sourceTabId) {
if ( !sourceTabId ) {
return false;
}
if ( !URI.schemeIs('http') && !URI.schemeIs('https') ) {
return false;
}
var result = vAPI.tabs.onPopup({
targetTabId: tabId,
openerTabId: sourceTabId,
targetURL: URI.asciiSpec
});
return result === true;
},
handleRequest: function(channel, URI, details) { handleRequest: function(channel, URI, details) {
var type = this.typeMap[details.type] || 'other'; var type = this.typeMap[details.type] || 'other';
var result; var result;
@ -1297,11 +1278,6 @@ var httpObserver = {
var channelData = oldChannel.getProperty(this.REQDATAKEY); var channelData = oldChannel.getProperty(this.REQDATAKEY);
if ( this.handlePopup(URI, channelData[3], channelData[2]) ) {
result = this.ABORT;
return;
}
var details = { var details = {
frameId: channelData[0], frameId: channelData[0],
parentFrameId: channelData[1], parentFrameId: channelData[1],
@ -1345,34 +1321,6 @@ vAPI.net.registerListeners = function() {
var details = e.data; var details = e.data;
var tabId = vAPI.tabs.getTabId(e.target); var tabId = vAPI.tabs.getTabId(e.target);
var sourceTabId = null; var sourceTabId = null;
// Popup candidate
if ( details.openerURL ) {
for ( var tab of vAPI.tabs.getAllSync() ) {
var URI = getBrowserForTab(tab).currentURI;
// Probably isn't the best method to identify the source tab
if ( URI.spec !== details.openerURL ) {
continue;
}
sourceTabId = vAPI.tabs.getTabId(tab);
if ( sourceTabId === tabId ) {
sourceTabId = null;
continue;
}
URI = Services.io.newURI(details.url, null, null);
if ( httpObserver.handlePopup(URI, tabId, sourceTabId) ) {
return;
}
break;
}
}
var lastRequest = httpObserver.lastRequest; var lastRequest = httpObserver.lastRequest;
lastRequest[1] = lastRequest[0]; lastRequest[1] = lastRequest[0];
lastRequest[0] = { lastRequest[0] = {

146
src/css/logger-ui.css

@ -21,6 +21,7 @@ body {
position: fixed; position: fixed;
top: 0; top: 0;
width: 100%; width: 100%;
z-index: 10;
} }
#toolbar .button { #toolbar .button {
background-color: white; background-color: white;
@ -35,6 +36,12 @@ body {
#toolbar .button:hover { #toolbar .button:hover {
background-color: #eee; background-color: #eee;
} }
body #compactViewToggler.button:before {
content: '\f102';
}
body.compactView #compactViewToggler.button:before {
content: '\f103';
}
body.filterOff #toolbar #filterButton { body.filterOff #toolbar #filterButton {
opacity: 0.25; opacity: 0.25;
} }
@ -48,73 +55,154 @@ input:focus {
background-color: #ffe; background-color: #ffe;
} }
#content { #content {
font: 13px sans-serif;
margin-top: 40px; margin-top: 40px;
width: 100%;
} }
#content table { #content table {
border: 0; border: 0;
border-collapse: collapse; border-collapse: collapse;
direction: ltr; direction: ltr;
font: 12px monospace;
table-layout: fixed;
width: 100%; width: 100%;
} }
#content table > colgroup > col:nth-of-type(1) {
width: 6em;
}
#content table > colgroup > col:nth-of-type(2) {
width: 3em;
}
#content table > colgroup > col:nth-of-type(3) {
width: 3em;
}
#content table > colgroup > col:nth-of-type(4) {
width: 8em;
}
#content table > colgroup > col:nth-of-type(5) {
width: calc(100% - 20em);
}
#content table tr { #content table tr {
background-color: #fafafa; background-color: #fafafa;
color: #444;
} }
#content table tr:nth-of-type(2n+1) {
background-color: #eee;
}
#content table tr.cat_info { #content table tr.cat_info {
color: #00f; color: #00f;
} }
#content table tr.blocked { #content table tr.blocked {
color: #f00; color: #f00;
} }
#content table tr:nth-of-type(2n+1) {
background-color: #eee;
}
#content table tr.doc { #content table tr.doc {
background-color: #666; background-color: #666;
color: white; color: white;
text-align: center; text-align: center;
} }
body:not(.filterOff) #content table tr.hidden { body:not(.filterOff) #content table tr.hidden {
display: none; display: none;
} }
#content table tr td {
body #content td {
border: 1px solid #ccc; border: 1px solid #ccc;
border-top: none;
min-width: 0.5em; min-width: 0.5em;
padding: 3px; padding: 3px;
vertical-align: top; vertical-align: top;
white-space: normal;
word-break: break-all;
word-wrap: break-word;
} }
#content table tr.doc > td {
border: 0;
#content table tr td {
border-top: 1px solid #ccc;
} }
#content table tr td:nth-of-type(1) {
text-align: center;
white-space: pre;
width: 8em;
#content table tr td:first-of-type {
border-left: none;
} }
#content table tr td:nth-of-type(2) {
width: 1em;
#content table tr td:last-of-type {
border-right: none;
} }
#content table tr td:nth-of-type(3) {
white-space: pre;
width: 2em;
body.compactView #content td {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
#content table tr td:nth-of-type(4) {
white-space: pre;
width: 8em;
#content table tr td:nth-of-type(1) {
text-align: center;
white-space: nowrap;
} }
#content table tr td:nth-of-type(5) {
border-right: none;
white-space: normal;
word-break: break-all;
word-wrap: break-word;
#content table tr td:nth-of-type(2) {
text-align: center;
white-space: nowrap;
} }
#content table tr.tab_bts > td:nth-of-type(2):before { #content table tr.tab_bts > td:nth-of-type(2):before {
content: '\f070'; content: '\f070';
font: 1em FontAwesome; font: 1em FontAwesome;
} }
#content table tr > td[colspan="3"]:nth-of-type(3) {
white-space: normal;
word-break: break-all;
word-wrap: break-word;
#content table tr.cat_net td:nth-of-type(2) {
cursor: zoom-in;
}
#content table tr.cat_net td:nth-of-type(3) {
font: 12px monospace;
text-align: center;
white-space: nowrap;
}
#content table tr.cat_net td:nth-of-type(5) {
}
#content table tr.cat_net td:nth-of-type(5) > span > span {
opacity: 0.6;
}
#content table tr.cat_net td:nth-of-type(5) > span > b {
font-weight: bold;
opacity: 1;
}
#popupContainer {
background: #444;
border: 1px solid gray;
cursor: -webkit-grab;
cursor: grab;
display: none;
overflow: hidden;
position: fixed;
z-index: 200;
}
#popupContainer.show {
display: block;
}
#popupContainer > iframe {
border: 0;
padding: 0;
margin: 1.5em 0 0 0;
width: 100%;
}
#focusOverlay {
bottom: 0;
cursor: not-allowed;
display: none;
left: 0;
position: fixed;
right: 0;
top: 0;
z-index: 100;
}
#popupContainer.show ~ #focusOverlay {
display: block;
}
#movingOverlay {
bottom: 0;
display: none;
left: 0;
position: fixed;
right: 0;
top: 0;
z-index: 300;
}
#popupContainer.moving ~ #movingOverlay {
cursor: -webkit-grabbing;
cursor: grabbing;
display: block;
} }

2
src/js/background.js

@ -62,7 +62,7 @@ return {
displayTextSize: '13px', displayTextSize: '13px',
externalHostsFiles: '', externalHostsFiles: '',
iconBadgeEnabled: true, iconBadgeEnabled: true,
maxLoggedRequests: 50,
maxLoggedRequests: 2000,
popupCollapseDomains: false, popupCollapseDomains: false,
popupCollapseSpecificDomains: {}, popupCollapseSpecificDomains: {},
popupHideBlacklisted: false, popupHideBlacklisted: false,

22
src/js/contentscript-end.js

@ -381,7 +381,7 @@ var nodesAddedHandler = function(nodeList, summary) {
case 'script': case 'script':
// https://github.com/gorhill/httpswitchboard/issues/252 // https://github.com/gorhill/httpswitchboard/issues/252
// Do not count µMatrix's own script tags, they are not required
// Do not count uMatrix's own script tags, they are not required
// to "unbreak" a web page // to "unbreak" a web page
if ( typeof node.id === 'string' && node.id.lastIndexOf('uMatrix-', 0) === 0 ) { if ( typeof node.id === 'string' && node.id.lastIndexOf('uMatrix-', 0) === 0 ) {
break; break;
@ -404,22 +404,6 @@ var nodesAddedHandler = function(nodeList, summary) {
summary.mustReport = true; summary.mustReport = true;
} }
break; break;
case 'object':
src = (node.data || '').trim();
if ( src !== '' ) {
summary.pluginSources[src] = true;
summary.mustReport = true;
}
break;
case 'embed':
src = (node.src || '').trim();
if ( src !== '' ) {
summary.pluginSources[src] = true;
summary.mustReport = true;
}
break;
} }
} }
}; };
@ -435,7 +419,6 @@ var nodeListsAddedHandler = function(nodeLists) {
what: 'contentScriptSummary', what: 'contentScriptSummary',
locationURL: window.location.href, locationURL: window.location.href,
scriptSources: {}, // to avoid duplicates scriptSources: {}, // to avoid duplicates
pluginSources: {}, // to avoid duplicates
mustReport: false mustReport: false
}; };
while ( i-- ) { while ( i-- ) {
@ -458,14 +441,13 @@ var nodeListsAddedHandler = function(nodeLists) {
what: 'contentScriptSummary', what: 'contentScriptSummary',
locationURL: window.location.href, locationURL: window.location.href,
scriptSources: {}, // to avoid duplicates scriptSources: {}, // to avoid duplicates
pluginSources: {}, // to avoid duplicates
mustReport: true mustReport: true
}; };
// https://github.com/gorhill/httpswitchboard/issues/25 // https://github.com/gorhill/httpswitchboard/issues/25
// & // &
// Looks for inline javascript also in at least one a[href] element. // Looks for inline javascript also in at least one a[href] element.
// https://github.com/gorhill/httpswitchboard/issues/131 // https://github.com/gorhill/httpswitchboard/issues/131
nodesAddedHandler(document.querySelectorAll('a[href^="javascript:"],embed,object,script'), summary);
nodesAddedHandler(document.querySelectorAll('a[href^="javascript:"],script'), summary);
//console.debug('contentscript-end.js > firstObservationHandler(): found %d script tags in "%s"', Object.keys(summary.scriptSources).length, window.location.href); //console.debug('contentscript-end.js > firstObservationHandler(): found %d script tags in "%s"', Object.keys(summary.scriptSources).length, window.location.href);

14
src/js/cookies.js

@ -224,22 +224,22 @@ var recordPageCookie = function(pageStore, cookieKey) {
} }
var cookieEntry = cookieDict[cookieKey]; var cookieEntry = cookieDict[cookieKey];
var block = µm.mustBlock(pageStore.pageHostname, cookieEntry.hostname, 'cookie');
var pageHostname = pageStore.pageHostname;
var block = µm.mustBlock(pageHostname, cookieEntry.hostname, 'cookie');
cookieLogEntryBuilder[0] = cookieURLFromCookieEntry(cookieEntry); cookieLogEntryBuilder[0] = cookieURLFromCookieEntry(cookieEntry);
cookieLogEntryBuilder[2] = cookieEntry.session ? 'session' : 'persistent'; cookieLogEntryBuilder[2] = cookieEntry.session ? 'session' : 'persistent';
cookieLogEntryBuilder[4] = encodeURIComponent(cookieEntry.name); cookieLogEntryBuilder[4] = encodeURIComponent(cookieEntry.name);
var cookieURL = cookieLogEntryBuilder.join('');
// rhill 2013-11-20: // rhill 2013-11-20:
// https://github.com/gorhill/httpswitchboard/issues/60 // https://github.com/gorhill/httpswitchboard/issues/60
// Need to URL-encode cookie name // Need to URL-encode cookie name
pageStore.recordRequest(
'cookie',
cookieLogEntryBuilder.join(''),
block
);
pageStore.recordRequest('cookie', cookieURL, block);
µm.logger.writeOne(pageStore.tabId, 'net', pageHostname, cookieURL, 'cookie', block);
cookieEntry.usedOn[pageStore.pageHostname] = true;
cookieEntry.usedOn[pageHostname] = true;
// rhill 2013-11-21: // rhill 2013-11-21:
// https://github.com/gorhill/httpswitchboard/issues/65 // https://github.com/gorhill/httpswitchboard/issues/65

12
src/js/httpsb.js

@ -134,17 +134,7 @@
} }
// Blocked by matrix filtering? // Blocked by matrix filtering?
if ( this.mustBlock(srcHostname, desHostname, type) ) {
return true;
}
// Cookies are not really requests, but are conveniently treated
// as such from matrix filtering point of view only.
if ( type === 'cookie' ) {
return false;
}
return false;
return this.mustBlock(srcHostname, desHostname, type);
}; };
/******************************************************************************/ /******************************************************************************/

260
src/js/logger-ui.js

@ -35,7 +35,6 @@
var messager = vAPI.messaging.channel('logger-ui.js'); var messager = vAPI.messaging.channel('logger-ui.js');
var inspectedTabId = ''; var inspectedTabId = '';
var maxEntries = 0;
var doc = document; var doc = document;
var body = doc.body; var body = doc.body;
var tbody = doc.querySelector('#content tbody'); var tbody = doc.querySelector('#content tbody');
@ -43,7 +42,9 @@ var trJunkyard = [];
var tdJunkyard = []; var tdJunkyard = [];
var firstVarDataCol = 2; // currently, column 2 (0-based index) var firstVarDataCol = 2; // currently, column 2 (0-based index)
var lastVarDataIndex = 3; // currently, d0-d3 var lastVarDataIndex = 3; // currently, d0-d3
var maxEntries = 5000;
var noTabId = ''; var noTabId = '';
var popupTabId;
var prettyRequestTypes = { var prettyRequestTypes = {
'main_frame': 'doc', 'main_frame': 'doc',
@ -53,15 +54,59 @@ var prettyRequestTypes = {
}; };
var timeOptions = { var timeOptions = {
month: 'short',
day: '2-digit',
hour: '2-digit', hour: '2-digit',
minute: '2-digit', minute: '2-digit',
second: '2-digit'
second: '2-digit',
hour12: false
};
var dateOptions = {
month: 'short',
day: '2-digit'
}; };
/******************************************************************************/ /******************************************************************************/
var escapeHTML = function(s) {
return s.replace(reEscapeLeftBracket, '<')
.replace(reEscapeRightBracket, '>');
};
var reEscapeLeftBracket = /</g;
var reEscapeRightBracket = />/g;
/******************************************************************************/
// Emphasize hostname in URL, as this is what matters in uMatrix's rules.
var nodeFromURL = function(url) {
var hnbeg = url.indexOf('://');
if ( hnbeg === -1 ) {
return document.createTextNode(url);
}
hnbeg += 3;
var hnend = url.indexOf('/', hnbeg);
if ( hnend === -1 ) {
hnend = url.slice(hnbeg).search(/\?#/);
if ( hnend !== -1 ) {
hnend += hnbeg;
} else {
hnend = url.length;
}
}
var node = renderedURLTemplate.cloneNode(true);
node.childNodes[0].textContent = url.slice(0, hnbeg);
node.childNodes[1].textContent = url.slice(hnbeg, hnend);
node.childNodes[2].textContent = url.slice(hnend);
return node;
};
var renderedURLTemplate = document.querySelector('#renderedURLTemplate > span');
/******************************************************************************/
var createCellAt = function(tr, index) { var createCellAt = function(tr, index) {
var td = tr.cells[index]; var td = tr.cells[index];
var mustAppend = !td; var mustAppend = !td;
@ -82,7 +127,7 @@ var createCellAt = function(tr, index) {
/******************************************************************************/ /******************************************************************************/
var createRow = function(entry) {
var createRow = function(layout) {
var tr = trJunkyard.pop(); var tr = trJunkyard.pop();
if ( tr ) { if ( tr ) {
tr.className = ''; tr.className = '';
@ -98,7 +143,7 @@ var createRow = function(entry) {
if ( i === lastVarDataIndex ) { if ( i === lastVarDataIndex ) {
break; break;
} }
if ( entry['d' + i] === undefined ) {
if ( layout.charAt(i) !== '1' ) {
span += 1; span += 1;
} else { } else {
if ( span !== 1 ) { if ( span !== 1 ) {
@ -122,7 +167,7 @@ var createRow = function(entry) {
/******************************************************************************/ /******************************************************************************/
var createGap = function(url) { var createGap = function(url) {
var tr = createRow({ d0: '' });
var tr = createRow('1');
tr.classList.add('doc'); tr.classList.add('doc');
tr.cells[firstVarDataCol].textContent = url; tr.cells[firstVarDataCol].textContent = url;
tbody.insertBefore(tr, tbody.firstChild); tbody.insertBefore(tr, tbody.firstChild);
@ -131,48 +176,53 @@ var createGap = function(url) {
/******************************************************************************/ /******************************************************************************/
var renderLogEntry = function(entry) { var renderLogEntry = function(entry) {
var tr;
var fvdc = firstVarDataCol; var fvdc = firstVarDataCol;
var tr = createRow(entry);
if ( entry.tab === noTabId ) {
tr.classList.add('tab_bts');
} else if ( entry.tab !== '' ) {
tr.classList.add('tab_' + entry.tab);
}
if ( entry.cat !== '' ) {
tr.classList.add('cat_' + entry.cat);
}
var time = new Date(entry.tstamp);
tr.cells[0].textContent = time.toLocaleString('fullwide', timeOptions);
switch ( entry.cat ) { switch ( entry.cat ) {
case 'error': case 'error':
case 'info': case 'info':
tr = createRow('1');
tr.cells[fvdc].textContent = entry.d0; tr.cells[fvdc].textContent = entry.d0;
break; break;
case 'net': case 'net':
tr = createRow('111');
// If the request is that of a root frame, insert a gap in the table // If the request is that of a root frame, insert a gap in the table
// in order to visually separate entries for different documents. // in order to visually separate entries for different documents.
if ( entry.d1 === 'doc' ) {
createGap(entry.d2);
if ( entry.d2 === 'doc' ) {
createGap(entry.d1);
} }
if ( entry.d0 ) {
if ( entry.d3 ) {
tr.classList.add('blocked'); tr.classList.add('blocked');
tr.cells[fvdc].textContent = '---'; tr.cells[fvdc].textContent = '---';
} else { } else {
tr.cells[fvdc].textContent = ''; tr.cells[fvdc].textContent = '';
} }
tr.cells[fvdc+1].textContent = (prettyRequestTypes[entry.d1] || entry.d1) + '\t';
tr.cells[fvdc+2].textContent = entry.d2 + '\t';
tr.cells[fvdc+1].textContent = (prettyRequestTypes[entry.d2] || entry.d2);
tr.cells[fvdc+2].appendChild(nodeFromURL(entry.d1));
break; break;
default: default:
tr = createRow('1');
tr.cells[fvdc].textContent = entry.d0; tr.cells[fvdc].textContent = entry.d0;
break; break;
} }
// Fields common to all rows.
var time = new Date(entry.tstamp);
tr.cells[0].textContent = time.toLocaleTimeString('fullwide', timeOptions);
tr.cells[0].title = time.toLocaleDateString('fullwide', dateOptions);
if ( entry.tab === noTabId ) {
tr.classList.add('tab_bts');
} else if ( entry.tab !== '' ) {
tr.classList.add('tab_' + entry.tab);
}
if ( entry.cat !== '' ) {
tr.classList.add('cat_' + entry.cat);
}
tbody.insertBefore(tr, tbody.firstChild); tbody.insertBefore(tr, tbody.firstChild);
}; };
@ -225,9 +275,9 @@ var renderLogBuffer = function(response) {
var truncateLog = function(size) { var truncateLog = function(size) {
if ( size === 0 ) { if ( size === 0 ) {
size = 25000;
size = 5000;
} }
size = Math.min(size, 25000);
size = Math.min(size, 5000);
var tr; var tr;
while ( tbody.childElementCount > size ) { while ( tbody.childElementCount > size ) {
tr = tbody.lastElementChild; tr = tbody.lastElementChild;
@ -238,6 +288,10 @@ var truncateLog = function(size) {
/******************************************************************************/ /******************************************************************************/
var onBufferRead = function(response) { var onBufferRead = function(response) {
if ( response.maxLoggedRequests !== maxEntries ) {
maxEntries = response.maxLoggedRequests;
uDom('#maxEntries').val(maxEntries || '');
}
renderLogBuffer(response); renderLogBuffer(response);
setTimeout(readLogBuffer, 1000); setTimeout(readLogBuffer, 1000);
}; };
@ -264,10 +318,146 @@ var clearBuffer = function() {
/******************************************************************************/ /******************************************************************************/
var reloadTab = function() {
messager.send({ what: 'reloadTab', tabId: inspectedTabId });
var toggleCompactView = function() {
body.classList.toggle(
'compactView',
body.classList.contains('compactView') === false
);
};
/******************************************************************************/
var togglePopup = (function() {
var container = null;
var movingOverlay = null;
var popup = null;
var popupObserver = null;
var style = null;
var styleTemplate = 'tr:not(.tab_{{tabId}}) { opacity: 0.1; }';
var dx, dy;
var moveTo = function(ev) {
container.style.left = (ev.clientX + dx) + 'px';
container.style.top = (ev.clientY + dy) + 'px';
};
var onMouseMove = function(ev) {
moveTo(ev);
ev.stopPropagation();
ev.preventDefault();
};
var onMouseUp = function(ev) {
moveTo(ev);
movingOverlay.removeEventListener('mouseup', onMouseUp);
movingOverlay.removeEventListener('mousemove', onMouseMove);
movingOverlay = null;
container.classList.remove('moving');
var rect = container.getBoundingClientRect();
vAPI.localStorage.setItem('popupLastPosition', JSON.stringify({
x: rect.left,
y: rect.top
}));
ev.stopPropagation();
ev.preventDefault();
};
var onMove = function(ev) {
container.classList.add('moving');
var rect = container.getBoundingClientRect();
dx = rect.left - ev.clientX;
dy = rect.top - ev.clientY;
movingOverlay = document.getElementById('movingOverlay');
movingOverlay.addEventListener('mousemove', onMouseMove, true);
movingOverlay.addEventListener('mouseup', onMouseUp, true);
ev.stopPropagation();
ev.preventDefault();
};
var resizePopup = function() {
var popupBody = popup.contentWindow.document.body;
if ( popupBody.clientWidth !== 0 && container.clientWidth !== popupBody.clientWidth ) {
container.style.width = popupBody.clientWidth + 'px';
}
if ( popupBody.clientHeight !== 0 && popup.clientHeight !== popupBody.clientHeight ) {
popup.style.height = popupBody.clientHeight + 'px';
}
};
var onLoad = function() {
resizePopup();
popupObserver.observe(popup.contentDocument.body, {
subtree: true,
attributes: true
});
};
var toggleOn = function(td) {
var tr = td.parentNode;
var matches = tr.className.match(/(?:^| )tab_([^ ]+)/);
if ( matches === null ) {
return;
}
var tabId = matches[1];
if ( tabId === 'bts' ) {
tabId = noTabId;
}
// Use last position if one is defined
var x, y;
var json = vAPI.localStorage.getItem('popupLastPosition');
if ( json ) {
try {
var popupLastPosition = JSON.parse(json);
x = popupLastPosition.x;
y = popupLastPosition.y;
}
catch (e) {
}
}
// Fall back to cell position if no position defined
if ( x === undefined ) {
var rect = td.getBoundingClientRect();
x = rect.left;
y = rect.bottom;
}
container = document.getElementById('popupContainer');
container.style.left = x + 'px';
container.style.top = y + 'px';
container.addEventListener('mousedown', onMove);
popup = container.querySelector('iframe');
popup.setAttribute('src', 'popup.html?tabId=' + tabId);
popup.addEventListener('load', onLoad);
popupObserver = new MutationObserver(resizePopup);
style = document.querySelector('#content > style');
style.textContent = styleTemplate.replace('{{tabId}}', tabId);
container.classList.add('show');
popupTabId = tabId;
}; };
var toggleOff = function() {
style.textContent = '';
style = null;
popupObserver.disconnect();
popupObserver = null;
popup.removeEventListener('load', onLoad);
popup.setAttribute('src', '');
popup = null;
container.classList.remove('show');
container.removeEventListener('mousedown', onMove);
container = null;
popupTabId = undefined;
};
return function(ev) {
if ( popupTabId !== undefined ) {
toggleOff();
} else {
toggleOn(ev.target);
}
};
})();
/******************************************************************************/ /******************************************************************************/
var onMaxEntriesChanged = function() { var onMaxEntriesChanged = function() {
@ -283,7 +473,7 @@ var onMaxEntriesChanged = function() {
messager.send({ messager.send({
what: 'userSettings', what: 'userSettings',
name: 'requestLogMaxEntries',
name: 'maxLoggedRequests',
value: maxEntries value: maxEntries
}); });
@ -299,17 +489,13 @@ uDom.onLoad(function() {
inspectedTabId = matches[1]; inspectedTabId = matches[1];
} }
var onSettingsReady = function(settings) {
maxEntries = settings.requestLogMaxEntries || 0;
uDom('#maxEntries').val(maxEntries || '');
};
messager.send({ what: 'getUserSettings' }, onSettingsReady);
readLogBuffer(); readLogBuffer();
uDom('#reload').on('click', reloadTab);
uDom('#compactViewToggler').on('click', toggleCompactView);
uDom('#clear').on('click', clearBuffer); uDom('#clear').on('click', clearBuffer);
uDom('#maxEntries').on('change', onMaxEntriesChanged); uDom('#maxEntries').on('change', onMaxEntriesChanged);
uDom('#content table').on('click', 'tr.cat_net > td:nth-of-type(2)', togglePopup);
uDom('#focusOverlay').on('click', togglePopup);
}); });
/******************************************************************************/ /******************************************************************************/

29
src/js/messaging.js

@ -269,11 +269,13 @@ var matrixSnapshot = function(tabId, details) {
/******************************************************************************/ /******************************************************************************/
var matrixSnapshotFromTabId = function(details, callback) { var matrixSnapshotFromTabId = function(details, callback) {
// Specific tab id requested?
if ( details.tabId ) { if ( details.tabId ) {
callback(matrixSnapshot(details.tabId, details)); callback(matrixSnapshot(details.tabId, details));
return; return;
} }
// Otherwise use tab id of current tab
vAPI.tabs.get(null, function(tab) { vAPI.tabs.get(null, function(tab) {
callback(matrixSnapshot(tab.id, details)); callback(matrixSnapshot(tab.id, details));
}); });
@ -373,6 +375,7 @@ var contentScriptSummaryHandler = function(tabId, details) {
} }
var pageStore = µm.pageStoreFromTabId(tabId); var pageStore = µm.pageStoreFromTabId(tabId);
var pageURL = pageStore.pageUrl; var pageURL = pageStore.pageUrl;
var pageHostname = pageStore.pageHostname;
var µmuri = µm.URI.set(details.locationURL); var µmuri = µm.URI.set(details.locationURL);
var frameURL = µmuri.normalizedURI(); var frameURL = µmuri.normalizedURI();
var frameHostname = µmuri.hostname; var frameHostname = µmuri.hostname;
@ -380,7 +383,7 @@ var contentScriptSummaryHandler = function(tabId, details) {
// https://github.com/gorhill/httpswitchboard/issues/333 // https://github.com/gorhill/httpswitchboard/issues/333
// Look-up here whether inline scripting is blocked for the frame. // Look-up here whether inline scripting is blocked for the frame.
var inlineScriptBlocked = µm.mustBlock(µm.scopeFromURL(pageURL), frameHostname, 'script');
var inlineScriptBlocked = µm.mustBlock(pageHostname, frameHostname, 'script');
// scripts // scripts
// https://github.com/gorhill/httpswitchboard/issues/25 // https://github.com/gorhill/httpswitchboard/issues/25
@ -394,23 +397,8 @@ var contentScriptSummaryHandler = function(tabId, details) {
url = frameURL + '{inline_script}'; url = frameURL + '{inline_script}';
} }
r = µm.filterRequest(pageURL, 'script', url); r = µm.filterRequest(pageURL, 'script', url);
pageStore.recordRequest('script', url, r !== false, r);
}
}
// TODO: as of 2014-05-26, not sure this is needed anymore, since µMatrix
// no longer uses chrome.contentSettings API (I think that was the reason
// this code was put in).
// plugins
// https://github.com/gorhill/httpswitchboard/issues/25
if ( pageStore ) {
urls = details.pluginSources;
for ( url in urls ) {
if ( !urls.hasOwnProperty(url) ) {
continue;
}
r = µm.filterRequest(pageURL, 'plugin', url);
pageStore.recordRequest('plugin', url, r !== false, r);
pageStore.recordRequest('script', url, r !== false);
µm.logger.writeOne(tabId, 'net', pageHostname, url, 'script', r);
} }
} }
@ -974,8 +962,9 @@ var onMessage = function(request, sender, callback) {
case 'readMany': case 'readMany':
response = { response = {
colorBlind: false, colorBlind: false,
noTabId: vAPI.noTabId,
entries: µm.logger.readAll(request.tabId)
entries: µm.logger.readAll(request.tabId),
maxLoggedRequests: µm.userSettings.maxLoggedRequests,
noTabId: vAPI.noTabId
}; };
break; break;

2
src/js/pagestats.js

@ -385,8 +385,6 @@ PageStore.prototype.recordRequest = function(type, url, block) {
this.perLoadAllowedRequestCount++; this.perLoadAllowedRequestCount++;
} }
µm.logger.writeOne(this.tabId, 'net', block ? '---' : '', type, url);
if ( !this.requests.createEntryIfNotExists(url, type, block) ) { if ( !this.requests.createEntryIfNotExists(url, type, block) ) {
return; return;
} }

12
src/js/popup.js

@ -1177,9 +1177,19 @@ var onMatrixSnapshotReady = function(response) {
/******************************************************************************/ /******************************************************************************/
var queryMatrixSnapshot = function(callback) { var queryMatrixSnapshot = function(callback) {
var tabId = matrixSnapshot.tabId;
// If no tab id yet, see if there is one specified in our URL
if ( tabId === undefined ) {
var matches = window.location.search.match(/(?:\?|&)tabId=([^&]+)/);
if ( matches !== null ) {
tabId = matches[1];
}
}
var request = { var request = {
what: 'matrixSnapshot', what: 'matrixSnapshot',
tabId: matrixSnapshot.tabId,
tabId: tabId,
tabURL: matrixSnapshot.url tabURL: matrixSnapshot.url
}; };
var snapshotReceived = function(response) { var snapshotReceived = function(response) {

5
src/js/storage.js

@ -406,6 +406,11 @@
µMatrix.assetUpdatedHandler = function(details) { µMatrix.assetUpdatedHandler = function(details) {
var path = details.path || ''; var path = details.path || '';
if ( path !== '' ) {
this.logger.writeOne('', 'info', 'asset updated: ' + path);
}
if ( this.liveHostsFiles.hasOwnProperty(path) === false ) { if ( this.liveHostsFiles.hasOwnProperty(path) === false ) {
return; return;
} }

6
src/js/tab.js

@ -607,9 +607,11 @@ vAPI.tabs.registerListeners();
µm.recordFromTabId = function(tabId, type, url, blocked) { µm.recordFromTabId = function(tabId, type, url, blocked) {
var pageStore = this.pageStoreFromTabId(tabId); var pageStore = this.pageStoreFromTabId(tabId);
if ( pageStore ) {
pageStore.recordRequest(type, url, blocked);
if ( pageStore === null ) {
return;
} }
pageStore.recordRequest(type, url, blocked);
this.logger.writeOne(tabId, 'net', pageStore.pageHostname, url, type, blocked);
}; };
/******************************************************************************/ /******************************************************************************/

21
src/js/traffic.js

@ -40,17 +40,18 @@ var onBeforeRootFrameRequestHandler = function(details) {
µm.tabContextManager.push(tabId, requestURL); µm.tabContextManager.push(tabId, requestURL);
var tabContext = µm.tabContextManager.mustLookup(tabId); var tabContext = µm.tabContextManager.mustLookup(tabId);
var rootHostname = tabContext.rootHostname;
var pageStore = µm.bindTabToPageStats(tabId); var pageStore = µm.bindTabToPageStats(tabId);
// Disallow request as per matrix? // Disallow request as per matrix?
var block = µm.mustBlock(tabContext.rootHostname, details.hostname, 'doc');
var block = µm.mustBlock(rootHostname, details.hostname, 'doc');
pageStore.recordRequest('doc', requestURL, block); pageStore.recordRequest('doc', requestURL, block);
µm.logger.writeOne(tabId, 'net', rootHostname, requestURL, 'doc', block);
// Not blocked // Not blocked
if ( !block ) { if ( !block ) {
// rhill 2013-11-07: Senseless to do this for behind-the-scene requests. // rhill 2013-11-07: Senseless to do this for behind-the-scene requests.
// rhill 2013-12-03: Do this here only for root frames.
µm.cookieHunter.recordPageCookies(pageStore); µm.cookieHunter.recordPageCookies(pageStore);
return; return;
} }
@ -114,20 +115,21 @@ var onBeforeRequestHandler = function(details) {
// https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275 // https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
var tabContext = µm.tabContextManager.mustLookup(details.tabId); var tabContext = µm.tabContextManager.mustLookup(details.tabId);
var tabId = tabContext.tabId; var tabId = tabContext.tabId;
var rootHostname = tabContext.rootHostname;
// Enforce strict secure connection? // Enforce strict secure connection?
var block = false; var block = false;
if ( if (
tabContext.secure && tabContext.secure &&
µm.URI.isSecureScheme(requestScheme) === false && µm.URI.isSecureScheme(requestScheme) === false &&
µm.tMatrix.evaluateSwitchZ('https-strict', tabContext.rootHostname)
µm.tMatrix.evaluateSwitchZ('https-strict', rootHostname)
) { ) {
block = true; block = true;
} }
// Disallow request as per temporary matrix? // Disallow request as per temporary matrix?
if ( block === false ) { if ( block === false ) {
block = µm.mustBlock(tabContext.rootHostname, details.hostname, requestType);
block = µm.mustBlock(rootHostname, details.hostname, requestType);
} }
// Record request. // Record request.
@ -136,8 +138,9 @@ var onBeforeRequestHandler = function(details) {
// processing has already been performed, and that a synthetic URL has // processing has already been performed, and that a synthetic URL has
// been constructed for logging purpose. Use this synthetic URL if // been constructed for logging purpose. Use this synthetic URL if
// it is available. // it is available.
var pageStore = µm.mustPageStoreFromTabId(tabContext.tabId);
var pageStore = µm.mustPageStoreFromTabId(tabId);
pageStore.recordRequest(requestType, requestURL, block); pageStore.recordRequest(requestType, requestURL, block);
µm.logger.writeOne(tabId, 'net', rootHostname, requestURL, requestType, block);
// Allowed? // Allowed?
if ( !block ) { if ( !block ) {
@ -198,6 +201,7 @@ var onBeforeSendHeadersHandler = function(details) {
if ( linkAuditor !== '' ) { if ( linkAuditor !== '' ) {
var block = µm.userSettings.processHyperlinkAuditing; var block = µm.userSettings.processHyperlinkAuditing;
pageStore.recordRequest('other', requestURL + '{Ping-To:' + linkAuditor + '}', block); pageStore.recordRequest('other', requestURL + '{Ping-To:' + linkAuditor + '}', block);
µm.logger.writeOne(tabId, 'net', '', requestURL, 'ping', block);
if ( block ) { if ( block ) {
µm.hyperlinkAuditingFoiledCounter += 1; µm.hyperlinkAuditingFoiledCounter += 1;
return { 'cancel': true }; return { 'cancel': true };
@ -293,7 +297,8 @@ var onMainDocHeadersReceived = function(details) {
// console.debug('onMainDocHeadersReceived()> "%s": %o', requestURL, details); // console.debug('onMainDocHeadersReceived()> "%s": %o', requestURL, details);
var blockScript = µm.mustBlock(tabContext.rootHostname, tabContext.rootHostname, 'script');
var rootHostname = tabContext.rootHostname;
var blockScript = µm.mustBlock(rootHostname, rootHostname, 'script');
// https://github.com/gorhill/httpswitchboard/issues/181 // https://github.com/gorhill/httpswitchboard/issues/181
var pageStore = µm.pageStoreFromTabId(tabId); var pageStore = µm.pageStoreFromTabId(tabId);
@ -305,7 +310,7 @@ var onMainDocHeadersReceived = function(details) {
return; return;
} }
µm.logger.writeOne(tabId, 'net', '---', 'inline-script', requestURL);
µm.logger.writeOne(tabId, 'net', rootHostname, requestURL + '{inline_script}', 'script', true);
// If javascript not allowed, say so through a `Content-Security-Policy` directive. // If javascript not allowed, say so through a `Content-Security-Policy` directive.
details.responseHeaders.push({ details.responseHeaders.push({
@ -356,7 +361,7 @@ var onSubDocHeadersReceived = function(details) {
// console.debug('onSubDocHeadersReceived()> FRAME CSP "%s": %o, scope="%s"', details.url, details, pageURL); // console.debug('onSubDocHeadersReceived()> FRAME CSP "%s": %o, scope="%s"', details.url, details, pageURL);
µm.logger.writeOne(tabId, 'net', '---', 'inline-script', details.url);
µm.logger.writeOne(tabId, 'net', tabContext.rootHostname, details.url + '{inline_script}', 'script', true);
// If javascript not allowed, say so through a `Content-Security-Policy` directive. // If javascript not allowed, say so through a `Content-Security-Policy` directive.
details.responseHeaders.push({ details.responseHeaders.push({

5
src/js/useragent.js

@ -1,7 +1,7 @@
/******************************************************************************* /*******************************************************************************
µMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014 Raymond Hill
uMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014-2015 Raymond Hill
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -60,6 +60,7 @@ var userAgentSpoofer = function(force) {
if ( uaStr === '' ) { if ( uaStr === '' ) {
µm.userAgentReplaceStr = userAgentRandomPicker(); µm.userAgentReplaceStr = userAgentRandomPicker();
µm.userAgentReplaceStrBirth = Date.now(); µm.userAgentReplaceStrBirth = Date.now();
µm.logger.writeOne('', 'info', 'spoofing user agent with: ' + µm.userAgentReplaceStr);
} }
}; };

24
src/logger-ui.html

@ -6,20 +6,38 @@
<link rel="stylesheet" type="text/css" href="css/logger-ui.css"> <link rel="stylesheet" type="text/css" href="css/logger-ui.css">
<title>uMatrix log</title> <title>uMatrix log</title>
</head> </head>
<body>
<body class="compactView">
<div id="toolbar"> <div id="toolbar">
<span id="reload" class="button fa">&#xf021;</span>
<span id="compactViewToggler" class="button fa"></span>
<span id="clear" class="button fa">&#xf12d;</span> <span id="clear" class="button fa">&#xf12d;</span>
<span id="filterButton" class="button fa">&#xf0b0;</span><input id="filterExpression" type="text" placeholder="logFilterPrompt"> <span id="filterButton" class="button fa">&#xf0b0;</span><input id="filterExpression" type="text" placeholder="logFilterPrompt">
<input id="maxEntries" type="text" size="5" title="logMaxEntriesTip"> <input id="maxEntries" type="text" size="5" title="logMaxEntriesTip">
</div> </div>
<div id="content"> <div id="content">
<table><tbody></tbody></table>
<style></style>
<table>
<colgroup><col><col><col><col><col></colgroup>
<tbody></tbody>
</table>
</div> </div>
<div id="popupContainer">
<iframe src></iframe>
</div>
<div id="focusOverlay"></div>
<div id="movingOverlay"></div>
<div style="display: none;">
<div id="renderedURLTemplate"><span><span></span><b></b><span></span></span></div>
</div>
<script src="js/vapi-common.js"></script> <script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script> <script src="js/vapi-client.js"></script>
<script src="js/udom.js"></script> <script src="js/udom.js"></script>
<script src="js/i18n.js"></script> <script src="js/i18n.js"></script>
<script src="js/logger-ui.js"></script> <script src="js/logger-ui.js"></script>
</body> </body>
</html> </html>
Loading…
Cancel
Save