1

I'm using the Chrome browser and I'm trying to edit running JavaScript which resides directly in an HTML file (the HTML file is served by an external host). I'd like it to be simple like changing HTML/CSS, yes I know JavaScript is different because it is stateful and it cannot be compared to HTML/CSS but still Chrome supports changing external js files, it just doesn't like when you tamper with inline JavaScript.

Possible solutions which I've thought already:

  • Greasemonkey / TamperMonkey / Injecting my own at runtime: Won't solve my problems because the script is nested into an anonymous scope and can't be accessed from outside.

  • Man in the middle proxy: Not feasible in the long run, and it takes too much to setup just for what I have to do (I'll keep it as last resort).

How can I solve this problem?

Paul Sweatte
  • 23,524
  • 7
  • 119
  • 253
Warrior
  • 563
  • 1
  • 6
  • 20

2 Answers2

1

Modifying Javascript

Javascript can be parsed with acorn or esprima.

The result is an AST in the ESTree (also known as Mozilla Parser API) format.

You can then make modifications to the AST. estraverse and other estools projects may be helpful.

Some guidelines about making automatic modifications to third-party Javascript:

  • You do not want thrown Errors in your code, propagating up the stack and affecting other code. In addition, you will almost always want to be notified about such Errors. Therefore, you should surround all injected code with a try-catch block.
  • If you declare variables in your injected code, you do not want them interfering with other code (as can occur through var hoisting). Therefore, you should wrap all injected code in an IIFE.
  • Try to avoid modifying anything or causing any side-effects in your injected code. This will make it more difficult for your modifications to be detected.

Once you are done, transform the AST back into Javascript code with escodegen.

Designing the proxy

Since apparently you cannot modify the Javascript at runtime, you must modify it before runtime – before it has been loaded. Therefore, you will need a man-in-the-middle HTTP proxy.

As you will be using Javascript libraries, such as acorn and escodegen, the proxy must also be written in Javascript. More specifically, Node.js

The browser will request the full URL from the proxy. For example, if there is a request to http://www.google.com, Chrome will send something like this to the proxy:

GET http://www.google.com HTTP/1.1
Host: www.google.com
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

When the proxy receives a request, it should make the same request to the origin server, proxying along most of the headers that it received. It should remove the Host, Remote-Addr, Http-Client-IP, and Proxy-Connection headers sent by the browser, as those are intended for the proxy. It should also send Accept-Encoding: identity to the origin server, to disable HTTP compression, which is annoying to deal with.

After the proxy has downloaded the original resource, it may modify it in any way, before sending it back to the browser.

Configuring Chrome to use the proxy

For obvious reasons, you do not want to permanently mess with system proxy settings or browser proxy settings. You do not want all of your network traffic funneled through your own handwritten, probably hackish, proxy.

The Chrome Extension API chrome.proxy will thus be helpful to you, for the following reasons:

  1. The proxy will only affect Chrome, and not other applications.
  2. You can use the bypass list to ensure only certain traffic goes through the proxy.
  3. You can enable or disable the proxy at any time.

To use this API, you must create a custom Chrome extension.

A better way: creating a dedicated app

The current solution includes three components:

  • Chrome, the browser.
  • The proxy, a Node.js application that modifies Javascript.
  • The proxy configurator, a Chrome extension that tells Chrome to use the proxy.

If you anticipate that all of this will become very complex, you can create a dedicated app for this, using NW.js. NW.js is very versatile, and you can essentially use it as programmable Chrome.

Benefits of this approach:

  1. NW.js disables the cross-origin policy for trusted code. Thus, you can create a cross-origin iframe (don't forget to add the nwdisable and nwfaketop attributes), and programmatically interact with it through jQuery.
  2. NW.js supports all Node.js APIs. You can make the proxy an integrated part of your app. You will no longer need to worry about manually launching and killing it, as you would need to do if the proxy was an external Node.js application.
  3. NW.js supports all Chrome Extension APIs, including chrome.proxy. You can make the proxy configurator an integrated part of your app.
MultiplyByZer0
  • 5,209
  • 3
  • 29
  • 46