8

I would like to know if its possible to get active WebSockets of a Website. An example would be: var x = document.findWebSocket(). The websockets would be listed in Chrome under the Network Tab (In the dev tools section). From there the websockets are listed under "WS". I want to be able to do x.emit(..); as well.

So far i could only come up with var x = new WebSocket("wss://exampleUrl.com/socket.io/?EIO=3&transport=websocket", "protocol1");. But this only adds a new Websocket with a different sid from the one that i want to emit messages from.

adding "&sid = {SID of Active Websocket}" would not work.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
yup123321
  • 93
  • 1
  • 3

2 Answers2

19

It's a bit hacky, but if you can inject code that runs before the site's code does (for example, with Tampermonkey and @run-at document-start), you can monkeypatch window.WebSocket so that whenever it's called, you add the created websocket to an array which you can examine later. For example, running the following on Stack Overflow:

// ==UserScript==
// @name             0 New Userscript
// @include          /^https://stackoverflow.com
// @run-at           document-start
// @grant            none
// ==/UserScript==

const sockets = [];
const nativeWebSocket = window.WebSocket;
window.WebSocket = function(...args){
  const socket = new nativeWebSocket(...args);
  sockets.push(socket);
  return socket;
};
setTimeout(() => {
  // or create a button which, when clicked, does something with the sockets
  console.log(sockets);
}, 1000);

results in [WebSocket] being logged (and you could proceed to do whatever you wanted to do with the instance, such as call emit).

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • This works, although i think i can give more context. This is regarding the site skribbl.io. It shares its canvas using websockets, and in python people dont have to get this "hacky". So maybe it works in js in a simpler way? – yup123321 Jan 26 '20 at 06:29
  • I'm pretty doubtful that there's any other easy option, unfortunately - if you're trying to do client-side tweaking, monkeypatching globals before the site's official script runs is sometimes the best way to do it, even if it seems hacky. You could also enable Chrome Local Overrides and then write your own code into the site's source code https://stackapps.com/questions/8531/ but that's a *lot* more complicated for the same results - other than saving a reference to the created object, there doesn't look to be a way to get a list of current instances – CertainPerformance Jan 26 '20 at 06:34
  • Is it possible for me to create my own websocket in chrome? i do get a session id as first message, but when i send "2probe" it returns 3 instead of 3probe – yup123321 Jan 27 '20 at 00:36
  • If you create a socket instance, then add an `open` listener to it, and then `.send` something, you should be able to communicate with the server. For example: https://stackoverflow.com/a/59098029 Beyond that, hard to say where the logic is failing without seeing the code – CertainPerformance Jan 27 '20 at 03:56
  • Yeah, the problem is i am connecting with a new session id. When i click "play" it creates the websocket with new session_id, which means i join a different lobby at the same time. – yup123321 Jan 29 '20 at 14:17
  • "Click play", what do you mean? There isn't anything about a play button (or a lobby) anywhere in the question (or the answer) – CertainPerformance Jan 30 '20 at 04:15
  • There's no need to monkeypatch _before_ any socket initialization. You can do it at any later point in time and get access to any socket that is sending something for example by monkeypatching `WebSocket.prototype.send` and saving the `this` (i.e. that socket instance) from there. – trollkotze Aug 02 '21 at 15:24
  • 1
    (of course that only works if the client ever sends something) – trollkotze Aug 02 '21 at 16:55
  • This is the correct idea and works most of the times. However, it will fail if the original code tries to access the property of `WebSocket` (e.g., `window.WebSocket.OPEN` would be `undefined`). To fix this, `Proxy` should be used to fix these edge cases. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy – lewisxy Jul 10 '23 at 03:30
9

You could collect all sockets in an array as soon as they send something:

const originalSend = WebSocket.prototype.send;
window.sockets = [];
WebSocket.prototype.send = function(...args) {
  if (window.sockets.indexOf(this) === -1)
    window.sockets.push(this);
  return originalSend.call(this, ...args);
};

Then later:

if (sockets.length > 0)
  sockets[0].send('hello');
trollkotze
  • 1,070
  • 1
  • 11
  • 19
  • 1
    This will work if *client* code calls `someSocket.send(..)`, but such a situation may well not occur. The server may send a message that the client processes, but the client does not send a message in reply - this situation is extremely common (probably the most common usage of sockets - for on-demand server to client communication). – CertainPerformance Aug 02 '21 at 16:10
  • I see. I didn't think a client socket that doesn't regularly send stuff was so common. But yeah, now thinking about it, probably it is. – trollkotze Aug 02 '21 at 16:55