// Jackbox Chat Tracker - Injected Script v3.2.0 // This script intercepts Kosmi's WebSocket connection to capture chat messages // NOTE: This runs in the PAGE CONTEXT, not extension context! // Store original WebSocket constructor const OriginalWebSocket = window.WebSocket; // Hook WebSocket constructor to capture Kosmi's WebSocket window.WebSocket = function(url, protocols) { const socket = new OriginalWebSocket(url, protocols); // Check if this is Kosmi's GraphQL WebSocket if (url.includes('engine.kosmi.io') || url.includes('gql-ws')) { console.log('[Jackbox Chat Tracker] WebSocket hook active'); // Notify content script that we found the socket window.postMessage({ type: 'JACKBOX_TRACKER_SOCKET_FOUND', url: url }, '*'); // Method 1: Hook addEventListener (for event listeners added later) const originalAddEventListener = socket.addEventListener.bind(socket); socket.addEventListener = function(type, listener, options) { if (type === 'message') { const wrappedListener = function(event) { // Forward to content script try { const data = JSON.parse(event.data); window.postMessage({ type: 'JACKBOX_TRACKER_WS_MESSAGE', data: data }, '*'); } catch (e) { // Not JSON, skip } // Then forward to original listener return listener.call(this, event); }; return originalAddEventListener(type, wrappedListener, options); } return originalAddEventListener(type, listener, options); }; // Method 2: Intercept the onmessage property setter (for direct assignment) let realOnMessage = null; const descriptor = Object.getOwnPropertyDescriptor(WebSocket.prototype, 'onmessage'); Object.defineProperty(socket, 'onmessage', { get: function() { return realOnMessage; }, set: function(handler) { // Create wrapped handler realOnMessage = function(event) { // Forward to content script try { const data = JSON.parse(event.data); window.postMessage({ type: 'JACKBOX_TRACKER_WS_MESSAGE', data: data }, '*'); } catch (e) { // Not JSON, skip } // ALWAYS call original handler if (handler) { handler.call(socket, event); } }; // Actually set it on the underlying WebSocket using the original descriptor if (descriptor && descriptor.set) { descriptor.set.call(socket, realOnMessage); } }, configurable: true }); } return socket; }; // Preserve the original constructor properties window.WebSocket.prototype = OriginalWebSocket.prototype; window.WebSocket.CONNECTING = OriginalWebSocket.CONNECTING; window.WebSocket.OPEN = OriginalWebSocket.OPEN; window.WebSocket.CLOSING = OriginalWebSocket.CLOSING; window.WebSocket.CLOSED = OriginalWebSocket.CLOSED;