- // ==UserScript==
- // @license MIT
- // @name CWSS
- // @version 1.1
- // @description Complete WebSocket Sniffer
- // @author 0vC4
- // @match http://*/*
- // @match https://*/*
- // @grant none
- // @run-at document-start
- // @namespace https://greasyfork.org/users/670183
- // ==/UserScript==
-
-
-
- /* usage:
- // priority => (event) -> Infinity .. -Infinity -> listener
- // "this" instance of "WebSocket" for all functions in "hook"
- hook {
- priority: Number,
- init?: Function(),
- send?: Function(data),
- open?: Function(event),
- message?: Function(event),
- close?: Function(event),
- }
-
- // @return CWSS
- CWSS.setHook(hook);
- CWSS.setHooks([hook, hook, ...] | hook, hook, ...);
- CWSS.sockets; // [WebSocket, WebSocket, ...];
- */
-
-
-
- const CWSS = (() => {
- const _hooks_ = 'hooks'; // all hooks WebSocket.prototype[_hooks_]
- const eventKey = key => key+'_listener'; // all event listeners WebSocket.prototype[eventKey('open'|'message'|'close')]
- const listeners = ['open', 'message', 'close']; // (+init&send hooks available by default)
-
- const proto = window.WebSocket.prototype;
-
- const def = Object.defineProperty;
- const hidden = (obj, key, value) => def(obj, key, {configurable: true, value});
- const rebase = (obj, key, list) => def(obj, key, {
- configurable: true,
- enumerable: true,
- set: func => list.push(func)
- });
- const native = (obj, value) => {
- obj.toString = function(){return Function.toString.call(value, ...arguments);};
- };
-
- const sockets = [];
- const hooks = (() => {
- if (_hooks_ in proto) return proto[_hooks_];
- hidden(proto, _hooks_, []);
- const hooks = proto[_hooks_];
- const {send, addEventListener} = proto;
-
-
- const pipe = (type, ...next) => function() {
- for (const hook of hooks.sort((a, b) => b.priority - a.priority)) {
- if (hook[type]) arguments = hook[type].call(this, ...arguments);
- if (!arguments) return;
- }
- next.flat().forEach(func => func.call(this, ...arguments));
- };
-
-
- proto.send = pipe('send', send);
- native(proto.send, send);
-
-
- proto.addEventListener = function() {
- const type = arguments[0];
- const func = arguments[1];
- const list = this[eventKey(type)];
- if (list) list.push(func);
- else addEventListener.call(this, ...arguments);
- }
- native(proto.addEventListener, addEventListener);
-
-
- const Ows = window.WebSocket;
- window.WebSocket = function() {
- const ws = new Ows(...arguments);
- sockets.push(ws);
-
- pipe('init').call(ws);
- for(const key of listeners) {
- const list_key = eventKey(key);
- const list = hidden(ws, list_key, [])[list_key];
- addEventListener.call(ws, key, pipe(key, list));
- rebase(ws, 'on'+key, list);
- }
-
- return ws;
- }
- for(const k in Ows) if (k != 'prototype') window.WebSocket[k] = Ows[k];
- for(const k in Ows.prototype) if (k != 'constructor') try {window.WebSocket.prototype[k] = Ows.prototype[k];} catch(e) {};
- WebSocket.prototype[_hooks_] = Ows.prototype[_hooks_];
- native(window.WebSocket, Ows);
-
-
- return hooks;
- })();
-
- const root = {
- sockets,
- setHook(hook) {
- hooks.push(hook);
- return root;
- },
- setHooks(..._hooks) {
- hooks.push(..._hooks.flat());
- return root;
- }
- };
-
- return root;
- })();
-
-
-
- // example
- CWSS.setHook({
- priority: 9,
- init() {
- console.log(`Open WebSocket channel by url: ${this.url}`, this);
- return arguments;
- },
- message(e) {
- console.log(`Got data:`, e.data);
- return arguments;
- },
- send(data) {
- console.log(`Sending data:`, data);
- return arguments;
- },
- });
- // 0vC4#7152