From d314193540a2098ba6a6aab1f378bc5ed8c88656 Mon Sep 17 00:00:00 2001 From: cottongin Date: Sun, 5 Apr 2026 05:49:26 -0400 Subject: [PATCH] Fix stale cmd/ scripts, export LoginWithChromedp, clean up vet warnings Update 5 cmd/ test utilities that referenced APIs that drifted after bridge refactors (NewBrowserAuthManager, bridge.NewConfig, changed function signatures). Rewrite test-kosmi and test-native to use NewGraphQLWSClient directly. Export LoginWithChromedp for use by cmd scripts. Fix redundant-newline vet warnings across 5 cmd/ files. Remove unreachable code and replace deprecated ioutil calls in bridge/helper/lottie_convert.go. Made-with: Cursor --- bridge/helper/lottie_convert.go | 8 ++- bridge/kosmi/browser_auth.go | 4 +- bridge/kosmi/kosmi.go | 2 +- cmd/compare-auth/main.go | 56 ++++++++++++++++--- cmd/extract-queries/main.go | 2 +- cmd/parse-har/main.go | 2 +- cmd/test-browser-auth/main.go | 43 ++++++++------- cmd/test-image-upload/main.go | 4 +- cmd/test-kosmi/main.go | 90 +++++++++++++++++++++++++++++++ cmd/test-native/main.go | 72 +++++++++++++------------ cmd/test-session/main.go | 2 +- cmd/test-websocket-direct/main.go | 2 +- 12 files changed, 213 insertions(+), 74 deletions(-) create mode 100644 cmd/test-kosmi/main.go diff --git a/bridge/helper/lottie_convert.go b/bridge/helper/lottie_convert.go index ffbe95d..57c859e 100644 --- a/bridge/helper/lottie_convert.go +++ b/bridge/helper/lottie_convert.go @@ -3,7 +3,6 @@ package helper import ( - "io/ioutil" "os" "os/exec" @@ -23,7 +22,7 @@ func CanConvertTgsToX() error { // This relies on an external command, which is ugly, but works. func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) error { // lottie can't handle input from a pipe, so write to a temporary file: - tmpInFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-input-*.tgs") + tmpInFile, err := os.CreateTemp(os.TempDir(), "matterbridge-lottie-input-*.tgs") if err != nil { return err } @@ -35,7 +34,7 @@ func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) erro }() // lottie can handle writing to a pipe, but there is no way to do that platform-independently. // "/dev/stdout" won't work on Windows, and "-" upsets Cairo for some reason. So we need another file: - tmpOutFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-output-*.data") + tmpOutFile, err := os.CreateTemp(os.TempDir(), "matterbridge-lottie-output-*.data") if err != nil { return err } @@ -64,7 +63,7 @@ func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) erro // 'stderr' already contains some parts of Stderr, because it was set to 'nil'. return stderr } - dataContents, err := ioutil.ReadFile(tmpOutFileName) + dataContents, err := os.ReadFile(tmpOutFileName) if err != nil { return err } @@ -82,7 +81,6 @@ func SupportsFormat(format string) bool { default: return false } - return false } func LottieBackend() string { diff --git a/bridge/kosmi/browser_auth.go b/bridge/kosmi/browser_auth.go index ecbb382..d897e4a 100644 --- a/bridge/kosmi/browser_auth.go +++ b/bridge/kosmi/browser_auth.go @@ -9,9 +9,9 @@ import ( "github.com/sirupsen/logrus" ) -// loginWithChromedp uses browser automation to log in and extract the JWT token. +// LoginWithChromedp uses browser automation to log in and extract the JWT token. // This is the proven implementation that successfully authenticates users. -func loginWithChromedp(email, password string, log *logrus.Entry) (string, error) { +func LoginWithChromedp(email, password string, log *logrus.Entry) (string, error) { log.Info("Starting browser automation for authentication...") // Create context with timeout diff --git a/bridge/kosmi/kosmi.go b/bridge/kosmi/kosmi.go index ee42da3..cd16050 100644 --- a/bridge/kosmi/kosmi.go +++ b/bridge/kosmi/kosmi.go @@ -82,7 +82,7 @@ func (b *Bkosmi) Connect() error { } else { // No valid cache, authenticate with browser b.Log.Info("Authenticating with email/password...") - token, err = loginWithChromedp(email, password, b.Log) + token, err = LoginWithChromedp(email, password, b.Log) if err != nil { return fmt.Errorf("authentication failed: %w", err) } diff --git a/cmd/compare-auth/main.go b/cmd/compare-auth/main.go index 3ae5460..79492e0 100644 --- a/cmd/compare-auth/main.go +++ b/cmd/compare-auth/main.go @@ -1,11 +1,14 @@ package main import ( + "bytes" "encoding/base64" "encoding/json" "fmt" + "net/http" "os" "strings" + "time" bkosmi "github.com/42wim/matterbridge/bridge/kosmi" "github.com/sirupsen/logrus" @@ -36,10 +39,9 @@ func main() { fmt.Println(strings.Repeat("=", 80)) fmt.Println() - // Get anonymous token + // Get anonymous token via HTTP (same mutation the client uses internally) fmt.Println("šŸ“ Step 1: Getting anonymous token...") - client := bkosmi.NewGraphQLWSClient("https://app.kosmi.io/room/@test", "@test", entry) - anonToken, err := client.GetAnonymousTokenForTest() + anonToken, err := getAnonymousToken() if err != nil { fmt.Printf("āŒ Failed to get anonymous token: %v\n", err) os.Exit(1) @@ -47,10 +49,9 @@ func main() { fmt.Printf("āœ… Anonymous token obtained (length: %d)\n", len(anonToken)) fmt.Println() - // Get authenticated token + // Get authenticated token via browser automation fmt.Println("šŸ“ Step 2: Getting authenticated token via browser...") - browserAuth := bkosmi.NewBrowserAuthManager(email, password, entry) - authToken, err := browserAuth.GetToken() + authToken, err := bkosmi.LoginWithChromedp(email, password, entry) if err != nil { fmt.Printf("āŒ Failed to get authenticated token: %v\n", err) os.Exit(1) @@ -134,6 +135,49 @@ func printClaims(claims map[string]interface{}) { } } +func getAnonymousToken() (string, error) { + mutation := map[string]interface{}{ + "query": `mutation { anonLogin { token } }`, + } + jsonBody, err := json.Marshal(mutation) + if err != nil { + return "", err + } + + client := &http.Client{Timeout: 10 * time.Second} + req, err := http.NewRequest("POST", "https://engine.kosmi.io/", bytes.NewReader(jsonBody)) + if err != nil { + return "", err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Referer", "https://app.kosmi.io/") + req.ContentLength = int64(len(jsonBody)) + + resp, err := client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + return "", fmt.Errorf("HTTP %d", resp.StatusCode) + } + + var result map[string]interface{} + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "", err + } + + if data, ok := result["data"].(map[string]interface{}); ok { + if anonLogin, ok := data["anonLogin"].(map[string]interface{}); ok { + if token, ok := anonLogin["token"].(string); ok { + return token, nil + } + } + } + return "", fmt.Errorf("no token in response") +} + func compareClaims(anon, auth map[string]interface{}) { allKeys := make(map[string]bool) for k := range anon { diff --git a/cmd/extract-queries/main.go b/cmd/extract-queries/main.go index 40ed623..6d35fcb 100644 --- a/cmd/extract-queries/main.go +++ b/cmd/extract-queries/main.go @@ -36,7 +36,7 @@ func main() { os.Exit(1) } - fmt.Println("=== WebSocket Messages ===\n") + fmt.Println("\n=== WebSocket Messages ===") for _, entry := range har.Log.Entries { for i, msg := range entry.WebSocketMessages { diff --git a/cmd/parse-har/main.go b/cmd/parse-har/main.go index 188c18b..f96eba4 100644 --- a/cmd/parse-har/main.go +++ b/cmd/parse-har/main.go @@ -68,7 +68,7 @@ func main() { } } - fmt.Println("=== WebSocket Operations (in order) ===\n") + fmt.Println("\n=== WebSocket Operations (in order) ===") msgCount := 0 for _, entry := range har.Log.Entries { diff --git a/cmd/test-browser-auth/main.go b/cmd/test-browser-auth/main.go index 2de6429..c13df1d 100644 --- a/cmd/test-browser-auth/main.go +++ b/cmd/test-browser-auth/main.go @@ -1,8 +1,11 @@ package main import ( + "encoding/base64" + "encoding/json" "fmt" "os" + "strings" bkosmi "github.com/42wim/matterbridge/bridge/kosmi" "github.com/sirupsen/logrus" @@ -23,7 +26,6 @@ func main() { email := os.Args[1] password := os.Args[2] - // Set up logging log := logrus.New() log.SetLevel(logrus.DebugLevel) entry := logrus.NewEntry(log) @@ -31,11 +33,7 @@ func main() { fmt.Println("šŸš€ Testing browser-based authentication...") fmt.Println() - // Create browser auth manager - browserAuth := bkosmi.NewBrowserAuthManager(email, password, entry) - - // Get token - token, err := browserAuth.GetToken() + token, err := bkosmi.LoginWithChromedp(email, password, entry) if err != nil { fmt.Printf("āŒ Authentication failed: %v\n", err) os.Exit(1) @@ -48,27 +46,32 @@ func main() { fmt.Printf("Token length: %d characters\n", len(token)) fmt.Println() - // Check if authenticated - if browserAuth.IsAuthenticated() { - fmt.Println("āœ… Token is valid") - } else { - fmt.Println("āŒ Token is invalid or expired") - } - - // Get user ID - userID := browserAuth.GetUserID() + userID := extractUserIDFromJWT(token) if userID != "" { fmt.Printf("User ID: %s\n", userID) + } else { + fmt.Println("(Could not extract user ID from token)") } fmt.Println() fmt.Println("šŸŽ‰ Test completed successfully!") } -func min(a, b int) int { - if a < b { - return a +func extractUserIDFromJWT(token string) string { + parts := strings.Split(token, ".") + if len(parts) != 3 { + return "" } - return b + payload, err := base64.RawURLEncoding.DecodeString(parts[1]) + if err != nil { + return "" + } + var claims map[string]interface{} + if err := json.Unmarshal(payload, &claims); err != nil { + return "" + } + if sub, ok := claims["sub"].(string); ok { + return sub + } + return "" } - diff --git a/cmd/test-image-upload/main.go b/cmd/test-image-upload/main.go index 3afb994..720ebd2 100644 --- a/cmd/test-image-upload/main.go +++ b/cmd/test-image-upload/main.go @@ -9,11 +9,11 @@ import ( ) func main() { - fmt.Println("=== Kosmi Image Upload Test ===\n") + fmt.Println("=== Kosmi Image Upload Test ===") // Test 1: Generate a room code image fmt.Println("1. Generating room code image for 'TEST'...") - imageData, err := jackbox.GenerateRoomCodeImage("TEST") + imageData, err := jackbox.GenerateRoomCodeImage("TEST", "Test Game") if err != nil { log.Fatalf("Failed to generate image: %v", err) } diff --git a/cmd/test-kosmi/main.go b/cmd/test-kosmi/main.go new file mode 100644 index 0000000..214a5d0 --- /dev/null +++ b/cmd/test-kosmi/main.go @@ -0,0 +1,90 @@ +package main + +import ( + "flag" + "fmt" + "os" + "os/signal" + "regexp" + "strings" + "syscall" + "time" + + bkosmi "github.com/42wim/matterbridge/bridge/kosmi" + "github.com/sirupsen/logrus" +) + +func main() { + roomURL := flag.String("room", "https://app.kosmi.io/room/@hyperspaceout", "Kosmi room URL") + debug := flag.Bool("debug", false, "Enable debug logging") + flag.Parse() + + log := logrus.New() + if *debug { + log.SetLevel(logrus.DebugLevel) + } else { + log.SetLevel(logrus.InfoLevel) + } + log.SetFormatter(&logrus.TextFormatter{FullTimestamp: true}) + + logger := log.WithField("bridge", "kosmi-test") + + logger.Info("Starting Kosmi bridge test") + logger.Infof("Room URL: %s", *roomURL) + + roomID, err := extractRoomID(*roomURL) + if err != nil { + logger.Fatalf("Failed to extract room ID: %v", err) + } + + // Empty token = anonymous access + client := bkosmi.NewGraphQLWSClient(*roomURL, roomID, "", logger) + + client.OnMessage(func(payload *bkosmi.NewMessagePayload) { + username := payload.Data.NewMessage.User.DisplayName + if username == "" { + username = payload.Data.NewMessage.User.Username + } + ts := time.Unix(payload.Data.NewMessage.Time, 0) + logger.Infof("Received message: [%s] %s: %s", + ts.Format("15:04:05"), username, payload.Data.NewMessage.Body) + }) + + logger.Info("Connecting to Kosmi...") + if err := client.Connect(); err != nil { + logger.Fatalf("Failed to connect to Kosmi: %v", err) + } + logger.Info("Successfully connected to Kosmi!") + + logger.Info("Listening for messages... Press Ctrl+C to exit") + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + + go func() { + time.Sleep(5 * time.Second) + logger.Info("Bridge is running. Messages from Kosmi will appear above.") + }() + + <-sigChan + logger.Info("Shutting down...") + + if err := client.Disconnect(); err != nil { + logger.Errorf("Error disconnecting: %v", err) + } + + logger.Info("Goodbye!") +} + +func extractRoomID(url string) (string, error) { + url = strings.TrimSuffix(url, "/") + re := regexp.MustCompile(`/room/(@?[a-zA-Z0-9_-]+)`) + matches := re.FindStringSubmatch(url) + if len(matches) >= 2 { + roomID := matches[1] + if !strings.HasPrefix(roomID, "@") { + roomID = "@" + roomID + } + return roomID, nil + } + return "", fmt.Errorf("could not extract room ID from URL: %s", url) +} diff --git a/cmd/test-native/main.go b/cmd/test-native/main.go index da51b70..332b288 100644 --- a/cmd/test-native/main.go +++ b/cmd/test-native/main.go @@ -2,84 +2,88 @@ package main import ( "flag" + "fmt" "os" "os/signal" + "regexp" + "strings" "syscall" "time" - "github.com/42wim/matterbridge/bridge" bkosmi "github.com/42wim/matterbridge/bridge/kosmi" "github.com/sirupsen/logrus" ) func main() { - // Parse command line flags roomURL := flag.String("room", "https://app.kosmi.io/room/@hyperspaceout", "Kosmi room URL") debug := flag.Bool("debug", false, "Enable debug logging") flag.Parse() - // Set up logger log := logrus.New() if *debug { log.SetLevel(logrus.DebugLevel) } else { log.SetLevel(logrus.InfoLevel) } - log.SetFormatter(&logrus.TextFormatter{ - FullTimestamp: true, - }) + log.SetFormatter(&logrus.TextFormatter{FullTimestamp: true}) - logger := log.WithField("bridge", "kosmi-test") + logger := log.WithField("bridge", "kosmi-native-test") - logger.Info("Starting Kosmi bridge test") + logger.Info("Starting Kosmi native WebSocket test") logger.Infof("Room URL: %s", *roomURL) - // Create bridge configuration - cfg := bridge.NewConfig("kosmi.test", logger) - cfg.SetString("RoomURL", *roomURL) - cfg.SetBool("Debug", *debug) - - // Create Kosmi bridge - b := bkosmi.New(cfg) - - // Connect to Kosmi - logger.Info("Connecting to Kosmi...") - if err := b.Connect(); err != nil { - logger.Fatalf("Failed to connect to Kosmi: %v", err) + roomID, err := extractRoomID(*roomURL) + if err != nil { + logger.Fatalf("Failed to extract room ID: %v", err) } - logger.Info("Successfully connected to Kosmi!") + client := bkosmi.NewGraphQLWSClient(*roomURL, roomID, "", logger) - // Start message listener - go func() { - for msg := range cfg.Remote { - logger.Infof("Received message: [%s] %s: %s", - msg.Timestamp.Format("15:04:05"), - msg.Username, - msg.Text) + client.OnMessage(func(payload *bkosmi.NewMessagePayload) { + username := payload.Data.NewMessage.User.DisplayName + if username == "" { + username = payload.Data.NewMessage.User.Username } - }() + ts := time.Unix(payload.Data.NewMessage.Time, 0) + logger.Infof("Received message: [%s] %s: %s", + ts.Format("15:04:05"), username, payload.Data.NewMessage.Body) + }) + + logger.Info("Connecting to Kosmi via native WebSocket...") + if err := client.Connect(); err != nil { + logger.Fatalf("Failed to connect: %v", err) + } + logger.Info("Successfully connected!") - // Wait for interrupt signal logger.Info("Listening for messages... Press Ctrl+C to exit") sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) - // Optional: Send a test message after 5 seconds go func() { time.Sleep(5 * time.Second) logger.Info("Bridge is running. Messages from Kosmi will appear above.") - logger.Info("To test sending messages, integrate with IRC or use the full Matterbridge setup") }() <-sigChan logger.Info("Shutting down...") - // Disconnect - if err := b.Disconnect(); err != nil { + if err := client.Disconnect(); err != nil { logger.Errorf("Error disconnecting: %v", err) } logger.Info("Goodbye!") } +func extractRoomID(url string) (string, error) { + url = strings.TrimSuffix(url, "/") + re := regexp.MustCompile(`/room/(@?[a-zA-Z0-9_-]+)`) + matches := re.FindStringSubmatch(url) + if len(matches) >= 2 { + roomID := matches[1] + if !strings.HasPrefix(roomID, "@") { + roomID = "@" + roomID + } + return roomID, nil + } + return "", fmt.Errorf("could not extract room ID from URL: %s", url) +} diff --git a/cmd/test-session/main.go b/cmd/test-session/main.go index 8efdbac..6c9453f 100644 --- a/cmd/test-session/main.go +++ b/cmd/test-session/main.go @@ -68,7 +68,7 @@ func main() { fmt.Println("āœ… WebSocket connected!") // Step 3: Listen for messages - fmt.Println("\nšŸ‘‚ Listening for messages (press Ctrl+C to exit)...\n") + fmt.Println("\nšŸ‘‚ Listening for messages (press Ctrl+C to exit)...") messageCount := 0 for { diff --git a/cmd/test-websocket-direct/main.go b/cmd/test-websocket-direct/main.go index 6db38c0..3dbd62c 100644 --- a/cmd/test-websocket-direct/main.go +++ b/cmd/test-websocket-direct/main.go @@ -61,7 +61,7 @@ func main() { fmt.Println("āœ… Subscribed!") // Listen for messages - fmt.Println("\nšŸ‘‚ Listening for messages (press Ctrl+C to exit)...\n") + fmt.Println("\nšŸ‘‚ Listening for messages (press Ctrl+C to exit)...") messageCount := 0 for {