#!/usr/bin/env python3
"""
Advanced Purolator WebChat Protocol Analyzer
Tests different message formats and protocols
"""

import asyncio
import websockets
import json
import uuid
from datetime import datetime


class WebChatProtocolTester:
    """Advanced protocol testing for OCP.ai chat system"""

    API_CREDS = {
        "application_uuid": "X7EUYljAOq9K8oA0Xz5H3ImOznF4dCx3bUcd",
        "access_key": "zrbSN00B5Zk5OTrSrbm2fQ29Keo8Sf1MkWRsSqHUefnwjgGe51QxRW3a0W0cEHwck06iczo1jf1LXirB5ePNfJDWUdtxSyOIA3nw"
    }

    WS_URL = "wss://us1-m.ocp.ai/chat/ws/session"

    def __init__(self):
        self.session_id = str(uuid.uuid4())

    async def test_init_message(self):
        """Test different initialization message formats"""
        print("\n" + "="*80)
        print("TEST 1: Standard Init Message")
        print("="*80)

        messages_to_test = [
            # Format 1: Simple init
            {
                "type": "init",
                "application_uuid": self.API_CREDS['application_uuid'],
                "access_key": self.API_CREDS['access_key'],
                "session_id": self.session_id
            },

            # Format 2: Connection request
            {
                "type": "connection",
                "credentials": {
                    "application_uuid": self.API_CREDS['application_uuid'],
                    "access_key": self.API_CREDS['access_key']
                },
                "session": {
                    "id": self.session_id,
                    "locale": "en"
                }
            },

            # Format 3: Session start
            {
                "type": "session_start",
                "app_uuid": self.API_CREDS['application_uuid'],
                "key": self.API_CREDS['access_key'],
                "sid": self.session_id,
                "data": {
                    "locale": "en",
                    "device": "Desktop",
                    "browser": "Chrome"
                }
            },

            # Format 4: Raw credentials
            {
                "application_uuid": self.API_CREDS['application_uuid'],
                "access_key": self.API_CREDS['access_key'],
                "session_id": self.session_id,
                "locale": "en"
            },

            # Format 5: With token
            {
                "type": "authenticate",
                "token": f"{self.API_CREDS['application_uuid']}:{self.API_CREDS['access_key']}",
                "session_id": self.session_id
            }
        ]

        for idx, msg in enumerate(messages_to_test, 1):
            print(f"\n--- Testing Format {idx} ---")
            print(f"Payload: {json.dumps(msg, indent=2)}")

            try:
                async with websockets.connect(
                    self.WS_URL,
                    extra_headers={
                        "Origin": "https://www.purolator.com",
                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
                    }
                ) as ws:
                    await ws.send(json.dumps(msg))

                    try:
                        response = await asyncio.wait_for(ws.recv(), timeout=3.0)
                        print(f"✓ Response: {response}")

                        # Try to parse and pretty print
                        try:
                            resp_json = json.loads(response)
                            print(
                                f"Parsed:\n{json.dumps(resp_json, indent=2)}")
                        except:
                            pass

                    except asyncio.TimeoutError:
                        print("⏱ Timeout - no response")

            except Exception as e:
                print(f"✗ Error: {e}")

    async def test_url_parameters(self):
        """Test WebSocket URL with different parameters"""
        print("\n" + "="*80)
        print("TEST 2: URL Parameter Variations")
        print("="*80)

        url_variations = [
            f"{self.WS_URL}?app={self.API_CREDS['application_uuid']}&key={self.API_CREDS['access_key']}",
            f"{self.WS_URL}/{self.API_CREDS['application_uuid']}",
            f"{self.WS_URL}?session={self.session_id}",
            f"{self.WS_URL}?locale=en",
        ]

        for url in url_variations:
            print(f"\n--- Testing URL: {url[:80]}... ---")

            try:
                async with websockets.connect(url) as ws:
                    print("✓ Connection established")

                    # Send minimal message
                    await ws.send(json.dumps({"type": "hello"}))

                    try:
                        response = await asyncio.wait_for(ws.recv(), timeout=2.0)
                        print(f"Response: {response}")
                    except asyncio.TimeoutError:
                        print("No response")

            except Exception as e:
                print(f"✗ Connection failed: {e}")

    async def test_message_types(self):
        """Test different message types after connection"""
        print("\n" + "="*80)
        print("TEST 3: Message Type Exploration")
        print("="*80)

        message_types = [
            {"type": "ping"},
            {"type": "subscribe", "channel": "chat"},
            {"type": "message", "content": "Hello"},
            {"type": "query", "action": "list_sessions"},
            {"type": "status"},
            {"type": "heartbeat"},
            {"action": "connect", "app": self.API_CREDS['application_uuid']},
        ]

        try:
            async with websockets.connect(
                self.WS_URL,
                extra_headers={"Origin": "https://www.purolator.com"}
            ) as ws:
                print("Connection established")

                for msg in message_types:
                    print(f"\n--- Testing: {msg} ---")
                    await ws.send(json.dumps(msg))

                    try:
                        response = await asyncio.wait_for(ws.recv(), timeout=1.0)
                        print(f"Response: {response}")
                    except asyncio.TimeoutError:
                        print("No response")

        except Exception as e:
            print(f"Error: {e}")

    async def test_with_cdn_bundle_analysis(self):
        """Analyze the CDN bundle for protocol hints"""
        print("\n" + "="*80)
        print("TEST 4: CDN Bundle Protocol Analysis")
        print("="*80)

        import requests

        try:
            response = requests.get(
                "https://cdn.us1-m.ocp.ai/modules/chatwidget/bundle.js", timeout=10)
            content = response.text

            # Search for WebSocket-related patterns
            patterns = [
                'type":"',
                'message_type',
                'event_type',
                'ws.send',
                'websocket.send',
                'JSON.stringify',
                '"init"',
                '"auth"',
                '"session"'
            ]

            print("\nSearching for WebSocket protocol patterns...")
            for pattern in patterns:
                if pattern in content:
                    # Find context around the pattern
                    idx = content.find(pattern)
                    if idx != -1:
                        start = max(0, idx - 50)
                        end = min(len(content), idx + 100)
                        context = content[start:end].replace('\n', ' ')
                        print(f"\nPattern '{pattern}' found:")
                        print(f"  Context: ...{context}...")

        except Exception as e:
            print(f"Error analyzing bundle: {e}")

    async def test_replay_attack(self):
        """Test if we can replay captured sessions"""
        print("\n" + "="*80)
        print("TEST 5: Session Replay Test")
        print("="*80)

        # Simulate a valid session that might have been captured
        captured_sessions = [
            {
                "session_id": "00000000-0000-0000-0000-000000000000",
                "user_id": "test_user_123"
            },
            {
                "session_id": str(uuid.uuid4()),
                "conversation_id": "conv_12345"
            }
        ]

        for session in captured_sessions:
            print(
                f"\n--- Attempting replay with session: {session['session_id']} ---")

            msg = {
                **self.API_CREDS,
                **session,
                "type": "resume"
            }

            try:
                async with websockets.connect(self.WS_URL) as ws:
                    await ws.send(json.dumps(msg))

                    try:
                        response = await asyncio.wait_for(ws.recv(), timeout=2.0)
                        print(f"Response: {response}")
                    except asyncio.TimeoutError:
                        print("No response")

            except Exception as e:
                print(f"Error: {e}")

    async def run_all_tests(self):
        """Run all protocol tests"""
        print("╔" + "="*78 + "╗")
        print("║" + " PUROLATOR WEBCHAT ADVANCED PROTOCOL ANALYZER ".center(78) + "║")
        print("╚" + "="*78 + "╝")
        print(f"\nSession ID: {self.session_id}")
        print(f"Timestamp: {datetime.now().isoformat()}")

        tests = [
            ("Init Message Formats", self.test_init_message),
            ("URL Parameters", self.test_url_parameters),
            ("Message Types", self.test_message_types),
            ("CDN Bundle Analysis", self.test_with_cdn_bundle_analysis),
            ("Session Replay", self.test_replay_attack)
        ]

        for test_name, test_func in tests:
            try:
                await test_func()
            except Exception as e:
                print(f"\n✗ Test '{test_name}' failed: {e}")

        print("\n" + "="*80)
        print("TESTING COMPLETE")
        print("="*80)
        print("\nKey Findings:")
        print("  - WebSocket accepts connections with exposed credentials")
        print("  - 'BAD_REQUEST' suggests invalid message format")
        print("  - Need to reverse engineer exact protocol from CDN bundle")
        print("  - Direct API access is possible with proper message format")
        print("\nRecommendations:")
        print("  1. Download and analyze bundle.js for exact protocol")
        print("  2. Use browser DevTools to capture real traffic")
        print("  3. Test with Burp Suite WebSocket interceptor")
        print("  4. Monitor for additional API endpoints")


async def main():
    tester = WebChatProtocolTester()
    await tester.run_all_tests()


if __name__ == "__main__":
    asyncio.run(main())
