Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an alternative to preprocessorScript for Chrome DevTools extensions?

I want to create a custom profiler for Javascript as a Chrome DevTools Extension. To do so, I'd have to instrument all Javascript code of a website (parse to AST, inject hooks, generate new source). This should've been easily possible using chrome.devtools.inspectedWindow.reload() and its parameter preprocessorScript described here: https://developer.chrome.com/extensions/devtools_inspectedWindow.

Unfortunately, this feature has been removed (https://bugs.chromium.org/p/chromium/issues/detail?id=438626) because nobody was using it.

Do you know of any other way I could achieve the same thing with a Chrome Extension? Is there any other way I can replace an incoming Javascript source with a changed version? This question is very specific to Chrome Extensions (and maybe extensions to other browsers), I'm asking this as a last resort before going a different route (e.g. dedicated app).

like image 453
Pat Avatar asked Oct 18 '22 08:10

Pat


1 Answers

Use the Chrome Debugging Protocol.

First, use DOMDebugger.setInstrumentationBreakpoint with eventName: "scriptFirstStatement" as a parameter to add a break-point to the first statement of each script.

Second, in the Debugger Domain, there is an event called scriptParsed. Listen to it and if called, use Debugger.setScriptSource to change the source.

Finally, call Debugger.resume each time after you edited a source file with setScriptSource.

Example in semi-pseudo-code:

// Prevent code being executed
cdp.sendCommand("DOMDebugger.setInstrumentationBreakpoint", {
  eventName: "scriptFirstStatement"
});

// Enable Debugger domain to receive its events
cdp.sendCommand("Debugger.enable");

cdp.addListener("message", (event, method, params) => {
  // Script is ready to be edited
  if (method === "Debugger.scriptParsed") {
    cdp.sendCommand("Debugger.setScriptSource", {
      scriptId: params.scriptId,
      scriptSource: `console.log("edited script ${params.url}");`
    }, (err, msg) => {
      // After editing, resume code execution.
      cdg.sendCommand("Debugger.resume");
    });        
  }
});

The implementation above is not ideal. It should probably listen to the breakpoint event, get to the script using the associated event data, edit the script and then resume. Listening to scriptParsed and then resuming the debugger are two things that shouldn't be together, it could create problems. It makes for a simpler example, though.

like image 142
Pat Avatar answered Nov 02 '22 05:11

Pat