google chrome extension - Injecting javascript variable before content script -


using background script background.js, need inject dynamic variable content script before injecting file inject.js content script. inject.js need have access variable , run it's code before scripts on page run. having difficulties accessing dynamic variable inject.js content script.

manifest.json

{ "name": "shape shifter", "version": "1.0", "description": "anti browser fingerprinting web extension. generates randomised values http request headers, javascript property values , javascript method return types.", "manifest_version": 2, "icons": {     "32": "icons/person-32.png",     "48": "icons/person-48.png" }, "background": {     "persistent": true,     "scripts": ["js/ua.js", "js/words.js", "js/lib/seedrandom.min.js", "js/random.js", "js/background.js"] }, "browser_action": {     "default_title": "shape shifter",     "default_icon": "icons/person-32.png",     "default_popup": "html/popup.html" }, "content_scripts": [   {     "run_at": "document_end",     "matches": ["<all_urls>"],     "js": ["js/inject.js"]    } ], "permissions": [     "webrequest",     "webrequestblocking",     "webnavigation",     "tabs",     "activetab",     "storage",     "<all_urls>" ], "web_accessible_resources": [     "js/ua.js",     "js/words.js",     "js/lib/seedrandom.min.js",     "js/random.js",     "js/api/document.js",     "js/api/navigator.js",     "js/api/canvas.js",     "js/api/history.js",     "js/api/battery.js",     "js/api/audio.js",     "js/api/element.js" ] 

}

background.js

"use strict";  console.log("background script running ...");  function getseed(origin) {     // storage object     var storage = window.localstorage;      // have seed in storage origin or not?     var seed = storage.getitem(origin);      if (seed === null) {         // initialise 32 byte buffer         seed = new uint8array(32);          // fill cryptographically random values         window.crypto.getrandomvalues(seed);          // save storage         storage.setitem(origin, seed);     }      return seed; }  // methods http headers function getacceptheader(seed) {     return "notyetimplemented"; } function getacceptcharsetheader(seed) {     return "notyetimplemented"; } function getacceptencodingheader(seed) {     return "notyetimplemented"; } function getacceptlanguageheader() {     // note: tor browser uses american english     return "en-us,en;q=0.5"; } function getauthorizationheader(seed) {     return "notyetimplemented"; } function getexpectheader(seed) {     return "notyetimplemented"; } function getfromheader(seed) {     return "notyetimplemented"; } function gethostheader(seed) {     return "notyetimplemented"; } function getifmatchheader(seed) {     return "notyetimplemented"; } function getifmodifiedsinceheader(seed) {     return "notyetimplemented"; } function getifnonematchheader(seed) {     return "notyetimplemented"; } function getifrangeheader(seed) {     return "notyetimplemented"; } function getifunmodifiedsinceheader(seed) {     return "notyetimplemented"; } function getmaxforwardsheader(seed) {     return "notyetimplemented"; } function getproxyauthorizationheader(seed) {     return "notyetimplemented"; } function getrangeheader(seed) {     return "notyetimplemented"; } function getrefererheader() {     // note: https://developer.mozilla.org/en-us/docs/web/api/document/referrer     // note: value empty string if user navigated page directly (not through link, but, example, via bookmark).     // note: since property returns string, not give dom access referring page.      // note: make websites think go them directly rather being referred.     return ""; } function getteheader(seed) {     return "notyetimplemented"; } function getuseragentheader(seed) {     math.seedrandom(seed);      return useragents[randomnumber(0, useragents.length)]; }  function rewritehttpheaders(e) {     // create url object url string     var serverurl = new url(e.url);      console.log(e);      // origin (hostname)     var origin = serverurl.hostname;      var seed = getseed(origin);      console.log("background - seed origin " + origin + ": " + seed);      (var header of e.requestheaders) {         if (header.name.tolowercase() === "accept") {         }         else if (header.name.tolowercase() === "accept-charset") {         }         else if (header.name.tolowercase() === "accept-encoding") {         }         else if (header.name.tolowercase() === "accept-language") {             header.value = getacceptlanguageheader();         }         else if (header.name.tolowercase() === "authorization") {         }         else if (header.name.tolowercase() === "expect") {         }         else if (header.name.tolowercase() === "from") {         }         else if (header.name.tolowercase() === "host") {         }         else if (header.name.tolowercase() === "if-match") {         }         else if (header.name.tolowercase() === "if-modified-since") {         }         else if (header.name.tolowercase() === "if-none-match") {         }         else if (header.name.tolowercase() === "if-range") {         }         else if (header.name.tolowercase() === "if-unmodified-since") {         }         else if (header.name.tolowercase() === "max-forwards") {         }         else if (header.name.tolowercase() === "proxy-authorization") {         }         else if (header.name.tolowercase() === "range") {         }         else if (header.name.tolowercase() === "referer") {             header.value = getrefererheader();         }         else if (header.name.tolowercase() === "te") {         }         else if (header.name.tolowercase() === "user-agent") {             header.value = getuseragentheader(seed);         }     }      return {requestheaders: e.requestheaders}; }  chrome.webrequest.onbeforesendheaders.addlistener(rewritehttpheaders, {urls: ["<all_urls>"]}, ["blocking", "requestheaders"]);  chrome.webnavigation.onbeforenavigate.addlistener(function(details) {     // create url object url string     var serverurl = new url(details.url);      // origin (hostname)     var origin = serverurl.hostname;      var seed = "some dynamic value";      console.log("injecting value");     chrome.tabs.executescript(details.tabid, {code: "var seed = '" + seed + "';console.log(seed);", runat: "document_start"}, function() {         console.log("value injected");     }); }); 

inject.js

(function() {   function inject(filepath) {     var script = document.createelement('script');     script.src = chrome.extension.geturl(filepath);     script.onload = function() {       this.remove();     };     (document.head || document.documentelement).appendchild(script);   }    function injecttext(text) {     var script = document.createelement('script');     script.textcontent = text;     script.onload = function() {       this.remove();     };     (document.head || document.documentelement).appendchild(script);   }    console.log("content script running");    console.log(seed); // seed not defined here ???    injecttext("var seed = 'hello';");   console.log("[info] injected seed ...");   inject("js/ua.js");   console.log("[info] injected ua ...");   inject("js/words.js");   console.log("[info] injected words ...");   inject("js/lib/seedrandom.min.js");   console.log("[info] injected seed random ...");   inject("js/random.js");   console.log("[info] injected random ...");   inject("js/api/document.js");   console.log("[info] injected document api ...");   inject("js/api/navigator.js");   console.log("[info] injected navigator api ...");   inject("js/api/canvas.js");   console.log("[info] injected canvas api ...");   inject("js/api/history.js");   console.log("[info] injected history api ...");   inject("js/api/battery.js");   console.log("[info] injected battery api ...");   inject("js/api/audio.js");   console.log("[info] injected audio api ...");   inject("js/api/element.js");   console.log("[info] injected element api ..."); })(); 

i error when trying log seed console:

inject.js:26 uncaught referenceerror: seed not defined     @ inject.js:26     @ inject.js:52 

any ideas?

this going tricky.

let's @ requirements.

inject.js need have access variable , run it's code before scripts on page run.

that's not how code works. inject.js executed @ document_end - happens after whole dom tree parsed, means after all page scripts have run (barring asynchronous parts , async script loading).

chrome has solution - can set execution document_start. code run before else, while dom still not parsed (so document empty). code does, should not create problems (it relies on document.documentelement, exist).

problem is, code has synchronous still enjoy "runs before else" property. chrome pause dom parsing long synchronous part of code runs, bets off merrily continues parse (and run code from) document.

this, example, disqualifies chrome.storage , messaging access asynchronous.

i need inject dynamic variable [on page load]

meaning cannot store in advance in synchronously-available storage (e.g. in localstorage or cookies of website), problematic anyway considering don't know domains in advance.

note, code in particular, may not of factor; "dynamic" value in fact fixed per domain. still don't know in advance domain visited, can @ least guarantee on second load there.

using background script background.js, need inject dynamic variable content script before injecting file [that still needs run before else on page]

that's tricky part. in fact, stated, it's impossible. you're trying catch, background, exact moment between navigation being committed, chrome switched page new domain, , execution of document_start script.

there no detectable gap there, , no way tell chrome wait. it's race condition have no hopes resolve.

you're trying use webnavigation.onbeforenavigate - before navigation committed. injectscript goes previous page even, rendering useless. if try other event, e.g . oncommitted, there's still no telling when injectscript treated. after script.

so, how work around this?

fortunately, there synchronous storage that's available content script can push information right before earliest of scripts executes.

cookies.

however, using chrome.cookies api won't help. need actively inject cookie value request on webrequest.onheadersreceived.

you have have value ready synchronously process blocking handler onheadersreceived, can add 1 set-cookie header , have available in document.cookies in inject.js.

// background.js function addseedcookie(details) {   seed = somethingsynchronous();   details.responseheaders.push({     name: "set-cookie",     value: `seed_goes_here=${seed};`   });   return {     responseheaders: details.responseheaders   }; }  chrome.webrequest.onheadersreceived.addlistener(   addseedcookie, {urls: ["<all_urls>"]}, ["blocking", "responseheaders"] );  // inject.js function getcookie(cookie) { // https://stackoverflow.com/a/19971550/934239   return document.cookie.split(';').reduce(function(prev, c) {     var arr = c.split('=');     return (arr[0].trim() === cookie) ? arr[1] : prev;   }, undefined); }  var seed = getcookie("seed_goes_here"); 

note: above code untested , serves illustrate idea.


Comments

Popular posts from this blog

angular - Ionic slides - dynamically add slides before and after -

minify - Minimizing css files -

Add a dynamic header in angular 2 http provider -