Files
IRC-kosmi-relay/FINDINGS.md
2025-10-31 16:17:04 -04:00

4.8 KiB

Kosmi API Reverse Engineering Findings

Key Discovery: HTTP POST Works!

After browser-based investigation, we discovered that Kosmi's GraphQL API works via HTTP POST, not just WebSocket!

Working Endpoint

POST https://engine.kosmi.io/
Content-Type: application/json

{
  "query": "{ __schema { types { name } } }"
}

Response: 200 OK with proper GraphQL response

WebSocket Issue

The WebSocket endpoint wss://engine.kosmi.io/gql-ws returns 403 Forbidden when connecting directly because:

  1. Missing Cookies: The browser has session cookies that aren't accessible via document.cookie (HTTP-only)
  2. Missing Headers: Likely needs Origin: https://app.kosmi.io header
  3. Session Required: May need to establish a session first via HTTP

Implementation Options

Option 1: HTTP POST with Polling (Recommended for Now)

Pros:

  • Works without authentication
  • Simple implementation
  • No WebSocket complexity

Cons:

  • Not real-time (need to poll)
  • Higher latency
  • More bandwidth usage

Implementation:

// Poll for new messages every 1-2 seconds
func (c *GraphQLClient) PollMessages() {
    ticker := time.NewTicker(2 * time.Second)
    for range ticker.C {
        // Query for messages since last timestamp
        messages := c.QueryMessages(lastTimestamp)
        // Process new messages
    }
}

Option 2: WebSocket with Session Cookies

Pros:

  • Real-time updates
  • Efficient (push-based)
  • Lower latency

Cons:

  • Requires session establishment
  • Need to handle cookies
  • More complex

Implementation:

// 1. First, establish session via HTTP
session := establishSession()

// 2. Then connect WebSocket with cookies
dialer := websocket.Dialer{
    Jar: session.CookieJar,
}
conn, _, err := dialer.Dial(wsURL, http.Header{
    "Origin": []string{"https://app.kosmi.io"},
    "Cookie": []string{session.Cookies},
})

Option 3: Hybrid Approach

Best of both worlds:

  1. Use HTTP POST for sending messages (mutations)
  2. Use HTTP POST polling for receiving messages (queries)
  3. Later upgrade to WebSocket when we figure out auth

Next Steps

Immediate (HTTP-based)

  1. Update graphql.go to use HTTP POST instead of WebSocket
  2. Implement message polling
  3. Test with actual Kosmi room
  4. Verify message sending works

Future (WebSocket-based)

  1. Figure out session establishment
  2. Extract cookies from browser or create session
  3. Update WebSocket connection to include cookies
  4. Switch from polling to real-time subscriptions

GraphQL Schema Discovery

From the introspection query, we found these types:

  • RootQueryType - For queries
  • RootMutationType - For mutations
  • Session - Session management
  • Success - Success responses

We need to explore the schema more to find:

  • Message query fields
  • Message mutation fields
  • Room/channel structures

Testing Commands

Test HTTP Endpoint

curl -X POST https://engine.kosmi.io/ \
  -H "Content-Type: application/json" \
  -d '{"query": "{ __schema { types { name } } }"}'

Test with Go

resp, err := http.Post(
    "https://engine.kosmi.io/",
    "application/json",
    strings.NewReader(`{"query": "{ __schema { types { name } } }"}`),
)

Browser Findings

Cookies Present

g_state={...}

Plus HTTP-only cookies we can't access.

User Agent

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36

Origin

https://app.kosmi.io

Recommendations

For MVP: Use HTTP POST with polling

  • Simpler to implement
  • Works without authentication
  • Good enough for initial testing
  • Can upgrade to WebSocket later

For Production: Figure out WebSocket auth

  • Better performance
  • Real-time updates
  • Lower bandwidth
  • Better user experience

Updated Architecture

IRC Message
    ↓
Matterbridge
    ↓
Kosmi Bridge (HTTP POST)
    ↓
POST https://engine.kosmi.io/
    ↓
Kosmi Room

Kosmi Room
    ↓
Poll https://engine.kosmi.io/ (every 2s)
    ↓
Kosmi Bridge
    ↓
Matterbridge
    ↓
IRC Message

Action Items

  1. Update graphql.go:

    • Replace WebSocket with HTTP client
    • Implement POST request method
    • Add polling loop for messages
  2. Test queries:

    • Find the correct query for fetching messages
    • Find the correct mutation for sending messages
    • Test with actual room ID
  3. Implement polling:

    • Poll every 1-2 seconds
    • Track last message timestamp
    • Only fetch new messages
  4. Document limitations:

    • Note the polling delay
    • Explain why WebSocket doesn't work yet
    • Provide upgrade path

Status: HTTP POST endpoint discovered and verified
Next: Implement HTTP-based client to replace WebSocket