diff --git a/extension/coverage.js b/extension/coverage.js index ed2e52a..543827c 100644 --- a/extension/coverage.js +++ b/extension/coverage.js @@ -36,35 +36,82 @@ function onCopyClick() { }); } -function preprocessor(src, url, fName) { - function instrumentSrc(src) { - // Make sure that we store the original src code in a map. - var saniUrl = (url.replace(/\/|\:|\.|\?/g, '-') + '---' + (Math.random().toFixed(4))); - var prefix = '(window.__originals = window.__originals || {});' + - 'window.__originals["' + saniUrl + '"] = "' + btoa(unescape(encodeURIComponent(src))) + '";'; - - return prefix + window.instrument(src, saniUrl); - } - if (url) { - return instrumentSrc(window.beautify(src)); - } else { - return src; - } +/* + If specified, this script evaluates into a function + that accepts three string arguments: the source to + preprocess, the URL of the source, and a function + name if the source is an DOM event handler. The + preprocessorerScript function should return a string + to be compiled by Chrome in place of the input source. + In the case that the source is a DOM event handler, + the returned source must compile to a single JS function. +*/ + +function processScripts() { + + var oldEval = window.eval; + window.eval = function() { +// console.log( 'eval', arguments ); + console.log( 'INS EVAL' ); + eval( window.beautify( window.instrument( arguments[ 0 ] ) ) ); + return oldEval.apply( window, arguments ); + } + + function instrumentURL( url ) { + + return new Promise( ( resolve, reject ) => { + + fetch( url, { mode: 'no-cors' } ).then( res => res.text() ).then( src => { + + var saniUrl = (url.replace(/\/|\:|\.|\?/g, '-') + '---' + (Math.random().toFixed(4))); + var prefix = '(window.__originals = window.__originals || {});' + + 'window.__originals["' + saniUrl + '"] = "' + btoa(unescape(encodeURIComponent(src))) + '";'; + + resolve( prefix + window.instrument(src, saniUrl) ); + + } ).catch( e => reject( e ) ); + + } ); + + } + + [].forEach.call( document.querySelectorAll( 'script' ), s => { + let src = s.getAttribute( 'src' ); + if( src ) { + console.log( 'INS URL', src ); + instrumentURL( src ).then( res => { oldEval( res ) ) } ).catch( e => console.log( e, src ) ); + } else { + console.log( 'INS SCRIPT' ); + oldEval( window.beautify( window.instrument( s.textContent ) ) ); + } + } ); + + [].forEach.call( document.querySelectorAll('*'), e => { + [].forEach.call( e.attributes, a => { + if( a.nodeName.match( /^on/gmi ) ){ + console.log( 'INS INLINE' ); + oldEval( window.beautify( window.instrument( a.nodeValue ) ) ); + } + } ) + } ); + } -var request = new XMLHttpRequest(); -request.open('GET', 'instrumenter.js', false); -request.send(null); -var instrumenterSrc = request.responseText +Promise.all( [ + fetch( chrome.extension.getURL( 'instrumenter.js' ) ).then( res => res.text() ).then( res => instrumenterSrc = res ), + fetch( chrome.extension.getURL( 'beautify.js' ) ).then( res => res.text() ).then( res => beautifySrc = res ) +] ).then( function() { -request.open('GET', 'beautify.js', false); -request.send(null); -var beautifySrc = request.responseText + //console.log( 'ready' ); + +} ); + +var intro = '';//'console.log("here starts the coverage injected script");'; function onGatherClick() { - chrome.devtools.inspectedWindow.reload({ - preprocessingScript: instrumenterSrc + beautifySrc + - '(' + preprocessor + ')', - }); + chrome.devtools.inspectedWindow.reload({ + injectedScript: intro + instrumenterSrc + beautifySrc + + processScripts + ';' + 'window.addEventListener("load",processScripts)' + }); } diff --git a/extension/manifest.json b/extension/manifest.json index 1a8e0dd..5867004 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -7,5 +7,8 @@ "background" : { "scripts": ["background.js"] }, + "permissions": [ + "" + ], "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" }