Ωmega
Ωmega

Reputation: 43673

JavaScript WebSocket class

I need to log WebSocket traffic, so I am about to write a Chrome Extension that would inject some JavaScript code that should do a trick.

WebSocket = new Proxy(WebSocket, {
  construct: (target, args) => {
    console.log('new WebSocket instance');
    return new target(...args);
  }
})

What method do I need to override to log messages sent and received?

How can I modify such messages sent/received? A simple working code would be greatly appreciated.

Upvotes: 0

Views: 241

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370759

Rather than a Proxy, I'd construct and return a plain WebSocket, with your own custom methods attached as needed:

const origWebSocket = window.WebSocket;
window.WebSocket = function(url) {
  const socket = new origWebSocket(url);
  socket.send = (msg) => {
    console.log('intercepted send:', msg);
    origWebSocket.prototype.send.call(socket, msg);
  };
  socket.addEventListener('message', (event) => {
    console.log('intercepted receive:', event.data);
  });
  return socket;
};

// patching done
const socket = new WebSocket('wss://echo.websocket.org');
socket.onopen = () => {
  socket.send('hi');
};

To also modify an incoming message, you can patch the onmessage property of the instance (and the addEventListener property too, if needed) so that, when a message is received, it goes through your custom function first before the user's callback runs:

const origWebSocket = window.WebSocket;
const origOnMessage = Object.getOwnPropertyDescriptor(WebSocket.prototype, 'onmessage').set;
window.WebSocket = function(url) {
  const socket = new origWebSocket(url);
  Object.defineProperty(socket, 'onmessage', {
    set(cb) {
      origOnMessage.call(socket, (e) => {
        // Have to use defineProperty because `data` is a getter on the prototype
        Object.defineProperty(e, 'data', { value: e.data + ' modified' });
        cb(e);
      });
    }
  });
  socket.send = (msg) => {
    console.log('intercepted send:', msg);
    origWebSocket.prototype.send.call(socket, msg);
  };
  socket.addEventListener('message', (event) => {
    console.log('intercepted receive:', event.data);
    event.data = 'foobar';
  });
  return socket;
};

// patching done
const socket = new WebSocket('wss://echo.websocket.org');
socket.onopen = () => {
  socket.send('hi');
};
socket.onmessage = e => console.log('consumer sees message:', e.data);

Upvotes: 1

Related Questions