package main import ( "context" "encoding/base64" "encoding/json" "flag" "fmt" "net/http" "os" "time" "github.com/gorilla/websocket" ) const ( userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" appVersion = "4364" wsURL = "wss://engine.kosmi.io/gql-ws" tokenURL = "https://engine.kosmi.io/" ) func main() { roomID := flag.String("room", "@hyperspaceout", "Room ID") testMode := flag.Int("mode", 1, "Test mode: 1=with-token, 2=no-auth, 3=origin-only") flag.Parse() fmt.Printf("Test Mode %d: Testing WebSocket connection to Kosmi\n\n", *testMode) var conn *websocket.Conn var err error switch *testMode { case 1: fmt.Println("Mode 1: Testing with JWT token (full auth)") conn, err = testWithToken(*roomID) case 2: fmt.Println("Mode 2: Testing without authentication") conn, err = testWithoutAuth() case 3: fmt.Println("Mode 3: Testing with Origin header only") conn, err = testWithOriginOnly() default: fmt.Fprintf(os.Stderr, "Invalid test mode: %d\n", *testMode) os.Exit(1) } if err != nil { fmt.Fprintf(os.Stderr, "āŒ Connection failed: %v\n", err) os.Exit(1) } fmt.Println("āœ… WebSocket connected successfully!") defer conn.Close() // Try to do the GraphQL-WS handshake fmt.Println("\nšŸ“¤ Sending connection_init...") if err := waitForAck(conn); err != nil { fmt.Fprintf(os.Stderr, "āŒ Handshake failed: %v\n", err) os.Exit(1) } fmt.Println("āœ… WebSocket handshake successful!") fmt.Println("\nšŸ“ Testing message subscription...") if err := subscribeToMessages(conn, *roomID); err != nil { fmt.Fprintf(os.Stderr, "āŒ Subscription failed: %v\n", err) os.Exit(1) } fmt.Println("āœ… Subscribed to messages!") fmt.Println("\nšŸ‘‚ Listening for messages (press Ctrl+C to exit)...") // Listen for messages for { var msg map[string]interface{} if err := conn.ReadJSON(&msg); err != nil { fmt.Fprintf(os.Stderr, "Error reading message: %v\n", err) break } msgType, _ := msg["type"].(string) fmt.Printf("šŸ“„ Received: %s\n", msgType) if msgType == "next" { payload, _ := msg["payload"].(map[string]interface{}) data, _ := payload["data"].(map[string]interface{}) if newMessage, ok := data["newMessage"].(map[string]interface{}); ok { body, _ := newMessage["body"].(string) user, _ := newMessage["user"].(map[string]interface{}) username, _ := user["displayName"].(string) if username == "" { username, _ = user["username"].(string) } fmt.Printf(" šŸ’¬ %s: %s\n", username, body) } } } } // testWithToken attempts connection with full JWT authentication func testWithToken(roomID string) (*websocket.Conn, error) { fmt.Println(" 1ļøāƒ£ Step 1: Acquiring JWT token...") // Try to get token from GraphQL endpoint token, err := acquireToken() if err != nil { return nil, fmt.Errorf("failed to acquire token: %w", err) } fmt.Printf(" āœ… Got token: %s...\n", truncate(token, 50)) fmt.Println(" 2ļøāƒ£ Step 2: Connecting WebSocket with token...") return connectWithToken(token) } // testWithoutAuth attempts direct connection with no headers func testWithoutAuth() (*websocket.Conn, error) { fmt.Println(" Connecting without any authentication...") dialer := websocket.Dialer{ Subprotocols: []string{"graphql-ws"}, } conn, resp, err := dialer.Dial(wsURL, nil) if resp != nil { fmt.Printf(" Response status: %d\n", resp.StatusCode) } return conn, err } // testWithOriginOnly attempts connection with just Origin header func testWithOriginOnly() (*websocket.Conn, error) { fmt.Println(" Connecting with Origin header only...") dialer := websocket.Dialer{ Subprotocols: []string{"graphql-ws"}, } headers := http.Header{ "Origin": []string{"https://app.kosmi.io"}, } conn, resp, err := dialer.Dial(wsURL, headers) if resp != nil { fmt.Printf(" Response status: %d\n", resp.StatusCode) } return conn, err } // acquireToken gets a JWT token from Kosmi's API func acquireToken() (string, error) { // First, let's try a few different approaches // Approach 1: Try empty POST (some APIs generate anonymous tokens) fmt.Println(" Trying empty POST...") token, err := tryEmptyPost() if err == nil && token != "" { return token, nil } fmt.Printf(" Empty POST failed: %v\n", err) // Approach 2: Try GraphQL anonymous login fmt.Println(" Trying GraphQL anonymous session...") token, err = tryGraphQLSession() if err == nil && token != "" { return token, nil } fmt.Printf(" GraphQL session failed: %v\n", err) // Approach 3: Try REST endpoint fmt.Println(" Trying REST endpoint...") token, err = tryRESTAuth() if err == nil && token != "" { return token, nil } fmt.Printf(" REST auth failed: %v\n", err) return "", fmt.Errorf("all token acquisition methods failed") } // tryEmptyPost tries posting an empty body func tryEmptyPost() (string, error) { client := &http.Client{Timeout: 10 * time.Second} req, err := http.NewRequest("POST", tokenURL, nil) if err != nil { return "", err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Referer", "https://app.kosmi.io/") req.Header.Set("User-Agent", userAgent) resp, err := client.Do(req) if err != nil { return "", err } defer resp.Body.Close() if resp.StatusCode != 200 { return "", fmt.Errorf("status %d", resp.StatusCode) } var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return "", err } // Try to extract token from various possible locations if token, ok := result["token"].(string); ok { return token, nil } if data, ok := result["data"].(map[string]interface{}); ok { if token, ok := data["token"].(string); ok { return token, nil } } return "", fmt.Errorf("no token in response: %+v", result) } // tryGraphQLSession tries a GraphQL mutation for anonymous session func tryGraphQLSession() (string, error) { query := map[string]interface{}{ "query": `mutation { createAnonymousSession { token } }`, } return postGraphQL(query) } // tryRESTAuth tries REST-style auth endpoint func tryRESTAuth() (string, error) { body := map[string]interface{}{ "anonymous": true, } jsonBody, _ := json.Marshal(body) client := &http.Client{Timeout: 10 * time.Second} req, err := http.NewRequest("POST", tokenURL+"auth/anonymous", nil) if err != nil { return "", err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Referer", "https://app.kosmi.io/") req.Header.Set("User-Agent", userAgent) req.Body = http.NoBody _ = jsonBody // silence unused warning resp, err := client.Do(req) if err != nil { return "", err } defer resp.Body.Close() if resp.StatusCode >= 400 { return "", fmt.Errorf("status %d", resp.StatusCode) } var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return "", err } if token, ok := result["token"].(string); ok { return token, nil } return "", fmt.Errorf("no token in response") } // postGraphQL posts a GraphQL query func postGraphQL(query map[string]interface{}) (string, error) { jsonBody, _ := json.Marshal(query) client := &http.Client{Timeout: 10 * time.Second} req, err := http.NewRequest("POST", tokenURL, nil) if err != nil { return "", err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Referer", "https://app.kosmi.io/") req.Header.Set("User-Agent", userAgent) req.Body = http.NoBody _ = jsonBody // silence unused resp, err := client.Do(req) if err != nil { return "", err } defer resp.Body.Close() if resp.StatusCode != 200 { return "", fmt.Errorf("status %d", resp.StatusCode) } var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return "", err } // Navigate nested response if data, ok := result["data"].(map[string]interface{}); ok { if session, ok := data["createAnonymousSession"].(map[string]interface{}); ok { if token, ok := session["token"].(string); ok { return token, nil } } } return "", fmt.Errorf("no token in response") } // connectWithToken connects WebSocket with JWT token func connectWithToken(token string) (*websocket.Conn, error) { dialer := websocket.Dialer{ Subprotocols: []string{"graphql-ws"}, } headers := http.Header{ "Origin": []string{"https://app.kosmi.io"}, "User-Agent": []string{userAgent}, } conn, resp, err := dialer.Dial(wsURL, headers) if err != nil { if resp != nil { fmt.Printf(" Response status: %d\n", resp.StatusCode) } return nil, err } // Send connection_init with token uaEncoded := base64.StdEncoding.EncodeToString([]byte(userAgent)) initMsg := map[string]interface{}{ "type": "connection_init", "payload": map[string]interface{}{ "token": token, "ua": uaEncoded, "v": appVersion, "r": "", }, } if err := conn.WriteJSON(initMsg); err != nil { conn.Close() return nil, fmt.Errorf("failed to send connection_init: %w", err) } return conn, nil } // waitForAck waits for connection_ack func waitForAck(conn *websocket.Conn) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() done := make(chan error, 1) go func() { var msg map[string]interface{} if err := conn.ReadJSON(&msg); err != nil { done <- err return } msgType, _ := msg["type"].(string) if msgType != "connection_ack" { done <- fmt.Errorf("expected connection_ack, got %s", msgType) return } fmt.Println("āœ… Received connection_ack") done <- nil }() select { case err := <-done: return err case <-ctx.Done(): return fmt.Errorf("timeout waiting for connection_ack") } } // subscribeToMessages subscribes to room messages func subscribeToMessages(conn *websocket.Conn, roomID string) error { query := fmt.Sprintf(` subscription { newMessage(roomId: "%s") { body time user { displayName username } } } `, roomID) subMsg := map[string]interface{}{ "id": "test-subscription-1", "type": "subscribe", "payload": map[string]interface{}{ "query": query, "variables": map[string]interface{}{}, }, } return conn.WriteJSON(subMsg) } // truncate truncates a string func truncate(s string, maxLen int) string { if len(s) <= maxLen { return s } return s[:maxLen] + "..." }