From f13860fed8ca4c70831dcf1d922f3e05ac0b1cb0 Mon Sep 17 00:00:00 2001 From: Jaume Sanchez Date: Fri, 16 Sep 2016 20:48:43 +0200 Subject: [PATCH 1/2] initial try to update to current chrome extensions APIs --- extension/coverage.js | 66 +++++++++++++++++++++++++---------------- extension/manifest.json | 3 ++ 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/extension/coverage.js b/extension/coverage.js index ed2e52a..5274338 100644 --- a/extension/coverage.js +++ b/extension/coverage.js @@ -36,35 +36,51 @@ 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); - } +function processScripts() { + + 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 ) { + instrumentURL( src ).then( res => { eval( window.beautify( res ) ) } ).catch( e => console.log( e, src ) ); + } else { + eval( window.beautify( window.instrument( s.textContent ) ) ); + } + } ); - if (url) { - return instrumentSrc(window.beautify(src)); - } else { - return src; - } } -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() { + + //console.log( 'ready' ); -request.open('GET', 'beautify.js', false); -request.send(null); -var beautifySrc = request.responseText +} ); + +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'" } From 3c170828507f51b7d58f4d6a350e025306adabf3 Mon Sep 17 00:00:00 2001 From: Jaume Sanchez Date: Sat, 17 Sep 2016 00:17:24 +0200 Subject: [PATCH 2/2] added support for eval and inline scripts --- extension/coverage.js | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/extension/coverage.js b/extension/coverage.js index 5274338..543827c 100644 --- a/extension/coverage.js +++ b/extension/coverage.js @@ -36,8 +36,28 @@ function onCopyClick() { }); } + +/* + 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 ) => { @@ -59,12 +79,23 @@ function processScripts() { [].forEach.call( document.querySelectorAll( 'script' ), s => { let src = s.getAttribute( 'src' ); if( src ) { - instrumentURL( src ).then( res => { eval( window.beautify( res ) ) } ).catch( e => console.log( e, src ) ); + console.log( 'INS URL', src ); + instrumentURL( src ).then( res => { oldEval( res ) ) } ).catch( e => console.log( e, src ) ); } else { - eval( window.beautify( window.instrument( s.textContent ) ) ); + 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 ) ) ); + } + } ) + } ); + } Promise.all( [