Itsnotlupus' MiddleMan

inspect/intercept/modify any network requests

Versión del día 12/08/2023. Echa un vistazo a la versión más reciente.

Este script no debería instalarse directamente. Es una biblioteca que utilizan otros scripts mediante la meta-directiva de inclusión // @require https://updategreasyfork.deno.dev/scripts/472943/1234299/Itsnotlupus%27%20MiddleMan.js

Autor
itsnotlupus
Versión
1.0.1
Creado
12/08/2023
Actualizado
12/08/2023
Tamaño
11.6 KB
Licencia
MIT

MiddleMan - insert yourself between a page and its network traffic

This places a layer of middleware between a page's codebase and the fetch() and XMLHttpRequest APIs they pretty much all rely on.

Using it is simple. You get one object, middleMan, and you can .addHook() and .removeHook() on it.

middleMan.addHook("https://example.com/your/route/*", {
    requestHandler(request) {
      console.log("snooped on request:", request);
    }
});

Your request handler can return nothing to keep the current Request unchanged.
It can return a different Request object to change what will happen over the network. It can also return a Response object, in which case the network request will be skipped altogether and the Response will be used instead.

Finally, it can return a Promise to either a Request or a Response.

Hooks are called in the order they were registered. Each hook is given the Request object obtained from the previous hook.
When a request hook returns a Response, no further request hooks are called.

middleMan.addHook(/https:\/\/example\.org\/foo/bar\/*.json/, {
    async responseHandler(response) {
        console.log("snooped on response:", response);
        const data = await response.json();
        data.topLevel = "IMPORTANT";
        return Response.json(data);
    }
});

In the example above, we used a regular expression for the route rather than a string with wildcards. Use whatever makes sense.

Response handlers work similarly to request handlers. They can return nothing to keep the current response, or they can return a new response. All matching response hooks are called in order.

That's the gist of it. Here's a little bit of middleware that logs all graphql requests and responses, and replaces "dog" with "cat" on Twitter:

middleMan.addHook("https://twitter.com/i/api/graphql/*", {
  requestHandler(request) {
    console.log("REQUEST HANDLER saw", request);
  },
  async responseHandler(response) {
    console.log("RESPONSE HANDLER saw", response);
    const data = await response.json();
    console.log("data=", data);

    function traverse(obj, check, mutate) {
      if (!obj || typeof obj != 'object') return;
      Object.keys(obj).forEach(k => {
        if (check(obj, k)) obj[k]=mutate(obj[k]);
        else traverse(obj[k], check, mutate);
      });
    }

    traverse(data, 
      (obj,key) => ['full_text','text','description'].includes(key) && typeof obj[key] == 'string', 
      s=> s.replace(/\bdog\b/ig, 'cat'));

    return Response.json(data);
  }
});

It produces results like this:

That's it. Have fun!

(Disclaimer: I just put this together. It's probably buggy. Very buggy. Proceed with caution.)