# Chat Summary: Native WebSocket Investigation - 2025-10-31 09:43:00

## Session Overview

**Date**: October 31, 2025, 09:43:00  
**Task**: Reverse engineer Kosmi WebSocket API to replace ChromeDP with native Go client  
**Status**: ⚠️ **BLOCKED - WebSocket server requires browser context**

## Problem Statement

The goal was to replace the resource-heavy ChromeDP implementation (~100-200MB RAM, 3-5s startup) with a lightweight native Go WebSocket client (~10-20MB RAM, <1s startup).

## Investigation Summary

### Phase 1: Authentication Data Capture ✅

Created `cmd/capture-auth/main.go` to intercept and log all authentication data from a working ChromeDP session.

**Key Findings**:
1. **JWT Token Discovery**: WebSocket uses JWT token in `connection_init` payload
2. **Token Structure**:
   ```json
   {
     "aud": "kosmi",
     "exp": 1793367309,  // 1 YEAR expiration!
     "sub": "a067ec32-ad5c-4831-95cc-0f88bdb33587",  // Anonymous user ID
     "typ": "access"
   }
   ```
3. **Connection Init Format**:
   ```json
   {
     "type": "connection_init",
     "payload": {
       "token": "eyJhbGc...",  // JWT token
       "ua": "TW96aWxs...",     // Base64-encoded User-Agent
       "v": "4364",              // App version
       "r": ""                   // Room (empty for anonymous)
     }
   }
   ```

4. **No Cookies Required**: The `g_state` cookie is not needed for WebSocket auth

**Output**: `auth-data.json` with 104 WebSocket frames captured, 77 network requests logged

### Phase 2: Direct Connection Tests ❌

Created three test programs to attempt native WebSocket connections:

**Test 1**: `cmd/test-websocket/main.go`
- Mode 1: With JWT token
- Mode 2: No authentication  
- Mode 3: Origin header only

**Test 2**: `cmd/test-websocket-direct/main.go`
- Direct WebSocket with captured JWT token
- All required headers (Origin, User-Agent, etc.)

**Test 3**: `cmd/test-session/main.go`
- Visit room page first to establish session
- Use cookies from session
- Connect WebSocket with token

**Results**: ALL tests returned `403 Forbidden` during WebSocket handshake

### Phase 3: Root Cause Analysis 🔍

**The Problem**:
- 403 occurs during WebSocket **handshake**, BEFORE `connection_init`
- This means the server rejects the connection based on the CLIENT, not the authentication
- ChromeDP works because it's a real browser
- Native Go client is detected and blocked

**Likely Causes**:
1. **TLS Fingerprinting**: Go's TLS implementation has a different fingerprint than Chrome
2. **Cloudflare Protection**: Server uses bot detection (Captcha/challenge)
3. **WebSocket Extensions**: Browser sends specific extensions we're not replicating
4. **CDN Security**: Via header shows "1.1 Caddy" - reverse proxy with security rules

**Evidence**:
```
Response headers from 403:
  Cache-Control: [max-age=0, private, must-revalidate]
  Server: [Cowboy]
  Via: [1.1 Caddy]
  Alt-Svc: [h3=":443"; ma=2592000]
```

## Files Created

1. `cmd/capture-auth/main.go` - Authentication data capture tool
2. `cmd/test-websocket/main.go` - Multi-mode WebSocket test tool
3. `cmd/test-websocket-direct/main.go` - Direct token-based test
4. `cmd/test-session/main.go` - Session-based connection test
5. `AUTH_FINDINGS.md` - Detailed authentication documentation
6. `WEBSOCKET_403_ANALYSIS.md` - Comprehensive 403 error analysis
7. `auth-data.json` - Captured authentication data (104 WS frames)

## Key Insights

### What We Learned

1. **Kosmi uses standard JWT authentication** - Well-documented format
2. **Tokens are long-lived** - 1 year expiration means minimal refresh needs
3. **Anonymous access works** - No login credentials needed
4. **GraphQL-WS protocol** - Standard protocol, not proprietary
5. **The blocker is NOT authentication** - It's client detection/fingerprinting

### Why ChromeDP Works

ChromeDP bypasses all protection because it:
- ✅ Is literally Chrome (correct TLS fingerprint)
- ✅ Executes JavaScript (passes challenges)
- ✅ Has complete browser context
- ✅ Sends all expected headers/extensions
- ✅ Looks like a real user to security systems

## Recommendations

### Option A: Optimize ChromeDP (RECOMMENDED ⭐)

**Rationale**:
- It's the ONLY approach that works 100%
- Security bypass is likely impossible without reverse engineering Cloudflare
- 100-200MB RAM is acceptable for a bridge service
- Startup time is one-time cost

**Optimizations**:
```go
// Use headless-shell instead of full Chrome (~50MB savings)
FROM chromedp/headless-shell:latest

// Reduce memory footprint
chromedp.Flag("single-process", true),
chromedp.Flag("disable-dev-shm-usage", true),
chromedp.Flag("disable-gpu", true),

// Keep instance alive (avoid restart cost)
type ChromeDPPool struct {
    instance *ChromeDPClient
    mu       sync.Mutex
}
```

**Expected Results**:
- Memory: ~100MB (vs ~200MB currently)
- Startup: 3-5s (one-time, then instant)
- Reliability: 100%

### Option B: Hybrid Token Caching

**IF** we could bypass 403 (which we can't):
```go
// Get token via ChromeDP once per year
token := getTokenViaChromeDPOnce()
cacheToken(token, 11*months)

// Use native WebSocket with cached token
conn := nativeWebSocketConnect(token)
```

**Problem**: Still returns 403, so this doesn't help

### Option C: HTTP POST Polling (FALLBACK)

From `FINDINGS.md` - HTTP POST works without authentication:
```bash
curl -X POST https://engine.kosmi.io/ \
  -H "Content-Type: application/json" \
  -d '{"query": "{ messages { id body } }"}'
```

**Pros**:
- ✅ No browser needed
- ✅ Lightweight
- ✅ No 403 errors

**Cons**:
- ❌ Not real-time (need to poll)
- ❌ Higher latency (1-2s minimum)
- ❌ More bandwidth
- ❌ Might still be rate-limited

## Decision Point

**Question for User**: Which approach do you prefer?

1. **Keep and optimize ChromeDP** (reliable, heavier)
   - Stick with what works
   - Optimize for memory/startup
   - Accept ~100MB overhead

2. **Try HTTP POST polling** (lighter, but not real-time)
   - Abandon WebSocket
   - Poll every 1-2 seconds
   - Accept latency trade-off

3. **Continue native WebSocket investigation** (might be futile)
   - Attempt TLS fingerprint spoofing
   - Try different Go TLS libraries
   - Reverse engineer Cloudflare protection
   - **Warning**: May never succeed

## Current Status

### Completed ✅
- [x] Capture authentication data from ChromeDP
- [x] Create test programs for direct WebSocket
- [x] Test all authentication combinations
- [x] Document findings and analysis

### Blocked ⚠️
- [ ] Implement native WebSocket client (403 Forbidden)
- [ ] Test message flow with native client (can't connect)
- [ ] Replace ChromeDP (no working alternative)

### Pending User Decision 🤔
- Which approach to pursue?
- Accept ChromeDP optimization?
- Try HTTP polling instead?
- Invest more time in security bypass?

## Files for Review

1. **AUTH_FINDINGS.md** - Complete authentication documentation
2. **WEBSOCKET_403_ANALYSIS.md** - Why native WebSocket fails
3. **auth-data.json** - Raw captured data
4. **cmd/capture-auth/** - Authentication capture tool
5. **cmd/test-*/** - Various test programs

## Next Steps (Pending Decision)

**If Option A (Optimize ChromeDP)**:
1. Research chromedp/headless-shell
2. Implement memory optimizations
3. Add Chrome instance pooling
4. Benchmark improvements
5. Update documentation

**If Option B (HTTP Polling)**:
1. Test HTTP POST queries
2. Implement polling loop
3. Handle rate limiting
4. Test latency impact
5. Document trade-offs

**If Option C (Continue Investigation)**:
1. Set up Wireshark to analyze browser traffic
2. Research TLS fingerprinting bypass
3. Test with different TLS libraries
4. Attempt Cloudflare bypass techniques
5. **Warning**: Success not guaranteed

## Conclusion

After extensive testing, **native Go WebSocket connections are blocked by Kosmi's infrastructure** (likely Cloudflare or similar). The ChromeDP approach, while heavier, is currently the **ONLY** working solution for real-time WebSocket communication.

**Recommendation**: Optimize ChromeDP rather than trying to bypass security measures.

---

**Time Spent**: ~2 hours  
**Tests Performed**: 7 different connection methods  
**Lines of Code**: ~800 (test tools + analysis)  
**Outcome**: ChromeDP remains necessary for WebSocket access

