CWSS

Complete WebSocket Sniffer

目前为 2022-01-16 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/438408/1009004/CWSS.js

  1. // ==UserScript==
  2. // @license MIT
  3. // @name CWSS
  4. // @version 1.1
  5. // @description Complete WebSocket Sniffer
  6. // @author 0vC4
  7. // @match http://*/*
  8. // @match https://*/*
  9. // @grant none
  10. // @run-at document-start
  11. // @namespace https://greasyfork.org/users/670183
  12. // ==/UserScript==
  13.  
  14.  
  15.  
  16. /* usage:
  17. // priority => (event) -> Infinity .. -Infinity -> listener
  18. // "this" instance of "WebSocket" for all functions in "hook"
  19. hook {
  20. priority: Number,
  21. init?: Function(),
  22. send?: Function(data),
  23. open?: Function(event),
  24. message?: Function(event),
  25. close?: Function(event),
  26. }
  27.  
  28. // @return CWSS
  29. CWSS.setHook(hook);
  30. CWSS.setHooks([hook, hook, ...] | hook, hook, ...);
  31. CWSS.sockets; // [WebSocket, WebSocket, ...];
  32. */
  33.  
  34.  
  35.  
  36. const CWSS = (() => {
  37. const _hooks_ = 'hooks'; // all hooks WebSocket.prototype[_hooks_]
  38. const eventKey = key => key+'_listener'; // all event listeners WebSocket.prototype[eventKey('open'|'message'|'close')]
  39. const listeners = ['open', 'message', 'close']; // (+init&send hooks available by default)
  40.  
  41. const proto = window.WebSocket.prototype;
  42.  
  43. const def = Object.defineProperty;
  44. const hidden = (obj, key, value) => def(obj, key, {configurable: true, value});
  45. const rebase = (obj, key, list) => def(obj, key, {
  46. configurable: true,
  47. enumerable: true,
  48. set: func => list.push(func)
  49. });
  50. const native = (obj, value) => {
  51. obj.toString = function(){return Function.toString.call(value, ...arguments);};
  52. };
  53.  
  54. const sockets = [];
  55. const hooks = (() => {
  56. if (_hooks_ in proto) return proto[_hooks_];
  57. hidden(proto, _hooks_, []);
  58. const hooks = proto[_hooks_];
  59. const {send, addEventListener} = proto;
  60.  
  61.  
  62. const pipe = (type, ...next) => function() {
  63. for (const hook of hooks.sort((a, b) => b.priority - a.priority)) {
  64. if (hook[type]) arguments = hook[type].call(this, ...arguments);
  65. if (!arguments) return;
  66. }
  67. next.flat().forEach(func => func.call(this, ...arguments));
  68. };
  69.  
  70.  
  71. proto.send = pipe('send', send);
  72. native(proto.send, send);
  73.  
  74.  
  75. proto.addEventListener = function() {
  76. const type = arguments[0];
  77. const func = arguments[1];
  78. const list = this[eventKey(type)];
  79. if (list) list.push(func);
  80. else addEventListener.call(this, ...arguments);
  81. }
  82. native(proto.addEventListener, addEventListener);
  83.  
  84.  
  85. const Ows = window.WebSocket;
  86. window.WebSocket = function() {
  87. const ws = new Ows(...arguments);
  88. sockets.push(ws);
  89.  
  90. pipe('init').call(ws);
  91. for(const key of listeners) {
  92. const list_key = eventKey(key);
  93. const list = hidden(ws, list_key, [])[list_key];
  94. addEventListener.call(ws, key, pipe(key, list));
  95. rebase(ws, 'on'+key, list);
  96. }
  97.  
  98. return ws;
  99. }
  100. for(const k in Ows) if (k != 'prototype') window.WebSocket[k] = Ows[k];
  101. for(const k in Ows.prototype) if (k != 'constructor') try {window.WebSocket.prototype[k] = Ows.prototype[k];} catch(e) {};
  102. WebSocket.prototype[_hooks_] = Ows.prototype[_hooks_];
  103. native(window.WebSocket, Ows);
  104.  
  105.  
  106. return hooks;
  107. })();
  108.  
  109. const root = {
  110. sockets,
  111. setHook(hook) {
  112. hooks.push(hook);
  113. return root;
  114. },
  115. setHooks(..._hooks) {
  116. hooks.push(..._hooks.flat());
  117. return root;
  118. }
  119. };
  120.  
  121. return root;
  122. })();
  123.  
  124.  
  125.  
  126. // example
  127. CWSS.setHook({
  128. priority: 9,
  129. init() {
  130. console.log(`Open WebSocket channel by url: ${this.url}`, this);
  131. return arguments;
  132. },
  133. message(e) {
  134. console.log(`Got data:`, e.data);
  135. return arguments;
  136. },
  137. send(data) {
  138. console.log(`Sending data:`, data);
  139. return arguments;
  140. },
  141. });
  142. // 0vC4#7152