Chrome extension: Block page items before access
Asked Answered
C

3

10

I am trying to do block items on a webpage but I want to do that, before they are loaded. So, e.g., I could use

chrome.webRequest.onBeforeRequest.addListener(...);

And redirect/cancel the request. But i want to inspect the actual content of the request. What I am doing right now, is starting a XMLHttpRequest to load the url/object myself, inspect the content, and block it if necessary. However, the main problem is that in fact, not many objects are blocked. This means, that each object is loaded twice: Once for "my inspection" and once, after I said "okay, you may load it".

How can I intercept the loading process, so that I can inspect it on the fly and pass on the data bytes if they are allowed?

Hope you understand my question, thanks :-)

Example of how I do it right now:

function shall_be_blocked(info){
  var xhr = new XMLHttpRequest();
  xhr.open("GET", file, false);
  //... #load the file and inspect the bytes
  if (xhr.responseText=="block it") {
     return true;
  }
  return false;
}

chrome.webRequest.onBeforeRequest.addListener(
  function(info) {
    ret = shall_be_blocked(info);
    if (ret ...){return {cancel:true};}//loads the file once, as it is getting blocked
    return {};//loads the file twice
  },
  {},["blocking"]
);
Czarina answered 22/12, 2016 at 10:44 Comment(1)
Have you tried using ServiceWorker?Pushcart
C
1

I was able to achieve what i was trying to do. The solution does not necessarily need extensions anymore, but to setup a proxy this might be useful. Afterwards, the solution (for the specified problem above) is as follows:

  • Use a chrome extension to use a proxy, in this case, localhost
  • Setup a proxyscript, e.g. using python, to route all traffic (and maybe install certificates, so HTTPs traffic may be analyzed as well)
  • => Man-in-the-middle established, analyze traffic and modify if needed

Yes, this is not really a solution to the problem of making a chrome extension do this somehow, but it is not possible yet (see https://bugs.chromium.org/p/chromium/issues/detail?id=104058).

Best regards, mutilis

Czarina answered 8/1, 2017 at 0:22 Comment(0)
P
4

You can use ServiceWorker to read original Response before returning content of original Response or new content.

if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("sw.js").then(function(reg) {
    console.log("register", reg);
  }).catch(function(err) {
    console.log("err", err);
  });
}

self.addEventListener("fetch", function(event) {
  if (event.request.url == "/path/to/fetched/resource/") {
    console.log("fetch", event);
    event.respondWith(
      fetch(event.request).then(function(response) {
        return response.text()
          .then(function(text) {
            if (text === "abc123") {
              return new Response("def456")
            } else {
              return new Response(text)
            }
          })
      })
    );
  }
});

plnkr https://plnkr.co/edit/MXGSZN1i3quvZhkI7fqe?p=preview

See What happens when you read a response?

Pushcart answered 1/1, 2017 at 8:25 Comment(7)
sadly, this is not working for extensions. the extension pages are monitored by the serviceWorker, but not all visited websites. if thats enough, this answer is very good, but not for the sake of extensions to monitor visited websites :(Czarina
@Czarina Can you describe "but not all visited websites"? And include at Question or create a gist gist.github.com of all relevant javascript used?Pushcart
I mean, that pages used by the extension are monitored, but other websites (e.g. my tabs) are not reviewed by the serviceWorker. So this does not work for my problem. But, if you have a look at the example extension: developer.chrome.com/extensions/examples/extensions/… it demonstrates a way to redirect requests. What i want to do, is cancel: true/false if the request loads certain content. For example, if the picture loaded includes a certain array of bytes, it is supposed to be canceled. What i am able to do is: ...........(next comment)Czarina
............. 1.) load the object myself (synchronous) 2.) check the content 3.) if it is okay, allow the request to be done (which will load the object again) ==> big overhead, as each allowed object is loaded twice. my specific problem: i want to load the object -once- and pass it to the request after inspecting it. or just drop it, if it contains a certain array of bytes :/ all in all: - synchronous => sucks - loading twice => sucksCzarina
The link was to download zip itself, not extensions sample page. The content has to be read at least once to process the data. You could use ReadableStream to read all content once, during read check for condition, at close of reader either pass result, or do not pass result as a ResponsePushcart
Yeah, the zip includes all files needed for an extension and is therefore a good example. However, the serviceworkers are not able to access -other- webpages traffic. What i want to do is intercept -all- traffic ongoing in all tabs. And this via extension. So all requests are supposed to be intercepted, traffic analysed and if needed, the request is supposed to be cancelled. i am able to do so, but only by loading each element twice, which is too much overhead. (onBeforeRequest, load url on my own, check it, if not okay: {cancel: true}... Your solution works again with service workersCzarina
and i am not able to get those working outside of the extension they are activated/registered in.Czarina
G
1

I believe you can use arraybuffers to read the content in real-time.

Here's an example of loading a file / page into a buffer;

var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";

oReq.onload = function (oEvent) {
  var arrayBuffer = oReq.response; // Note: not oReq.responseText
  if (arrayBuffer) {
    var byteArray = new Uint8Array(arrayBuffer);
    for (var i = 0; i < byteArray.byteLength; i++) {
      // do something with each byte in the array
    }
  }
};

oReq.send(null);

This is a piece of code found on the XMLHttpRequest documentation page. Link.

Gluttony answered 27/12, 2016 at 14:52 Comment(4)
I know how to load the object myself, but i want to intercept the loading process of chrome. so Chrome loads a javascript e.g., i want to have a look at it, and if it is okay, i want to say chrome "yeah, you may display/use it. But if its not okay, i want to block it. i only found the way as seen in my question (which is loading each "allowed" object -twice-, which is the problem)Czarina
Doesn't this code does exactly that? I haven't tried it, but it seems like this would return a buffer while its loading. Another option would be making 1 endpoint that returns blocked items without content, and unblocked items with content? This way you'll only have 1 call and all resides on the server (in case you're using PHP it would also save bootstrapping the application on the server).Gluttony
but it is actually requesting a file/page itself. i want the user to surf the internet and when he wants to load a page, i want to intercept the loading. so the onload function looks okay, but i dont want to start the XMLHttpRequest, the user is supposed to this. Should be like this: User visits google.de. (...) website loads somescript.js -> extension looks at the bytes -> if allowed then pass_on() else block_it()Czarina
And what about loading the file into memory (into a variable or something) once, then check if you're allowed (look at bytes), and then if its OK inject it into the page. Allthough, from what I'm seeing you want to check the size of a file before downloading it (because of some bandwidth-saving browser plugin?) In that case I'm not sure if you can with the XMLHttpRequest.. You could with a TCP connection, request the file, read the headers, and continue if headers are OK. I think doing this with a plugin / in-browser only is going to be very hard...Gluttony
C
1

I was able to achieve what i was trying to do. The solution does not necessarily need extensions anymore, but to setup a proxy this might be useful. Afterwards, the solution (for the specified problem above) is as follows:

  • Use a chrome extension to use a proxy, in this case, localhost
  • Setup a proxyscript, e.g. using python, to route all traffic (and maybe install certificates, so HTTPs traffic may be analyzed as well)
  • => Man-in-the-middle established, analyze traffic and modify if needed

Yes, this is not really a solution to the problem of making a chrome extension do this somehow, but it is not possible yet (see https://bugs.chromium.org/p/chromium/issues/detail?id=104058).

Best regards, mutilis

Czarina answered 8/1, 2017 at 0:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.