From 476d0761729b0f0f1e723750ba317de34c9daad1 Mon Sep 17 00:00:00 2001 From: LifeRIP <89425013+LifeRIP@users.noreply.github.com> Date: Fri, 16 May 2025 12:46:36 -0500 Subject: [PATCH] feat: Update WebSocket API to require Firebase Auth Token in the query params URL --- docs/docs.go | 14 +++++---- docs/swagger.json | 14 +++++---- docs/swagger.yaml | 8 ++++-- internal/handlers/websocket_handler.go | 33 +++++++++++++++++----- internal/routes/router.go | 39 +++++++++++++------------- 5 files changed, 70 insertions(+), 38 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 531f430..0cfd7bb 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -609,11 +609,6 @@ const docTemplate = `{ }, "/chat/ws": { "get": { - "security": [ - { - "BearerAuth": [] - } - ], "description": "Establece una conexión WebSocket para mensajería en tiempo real", "consumes": [ "application/json" @@ -625,6 +620,15 @@ const docTemplate = `{ "Chat" ], "summary": "Conexión WebSocket para chat en tiempo real", + "parameters": [ + { + "type": "string", + "description": "Firebase Auth Token", + "name": "token", + "in": "query", + "required": true + } + ], "responses": { "101": { "description": "Switching Protocols a WebSocket", diff --git a/docs/swagger.json b/docs/swagger.json index f2b2da9..83a41ad 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -602,11 +602,6 @@ }, "/chat/ws": { "get": { - "security": [ - { - "BearerAuth": [] - } - ], "description": "Establece una conexión WebSocket para mensajería en tiempo real", "consumes": [ "application/json" @@ -618,6 +613,15 @@ "Chat" ], "summary": "Conexión WebSocket para chat en tiempo real", + "parameters": [ + { + "type": "string", + "description": "Firebase Auth Token", + "name": "token", + "in": "query", + "required": true + } + ], "responses": { "101": { "description": "Switching Protocols a WebSocket", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index d48e44c..ccf6a41 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -503,6 +503,12 @@ paths: consumes: - application/json description: Establece una conexión WebSocket para mensajería en tiempo real + parameters: + - description: Firebase Auth Token + in: query + name: token + required: true + type: string produces: - application/json responses: @@ -514,8 +520,6 @@ paths: description: No autorizado schema: type: string - security: - - BearerAuth: [] summary: Conexión WebSocket para chat en tiempo real tags: - Chat diff --git a/internal/handlers/websocket_handler.go b/internal/handlers/websocket_handler.go index abc6b10..ba23216 100644 --- a/internal/handlers/websocket_handler.go +++ b/internal/handlers/websocket_handler.go @@ -3,6 +3,7 @@ package handlers import ( "log" "net/http" + "strings" "github.com/Parchat/backend/internal/config" pws "github.com/Parchat/backend/internal/pkg/websocket" @@ -38,15 +39,33 @@ func NewWebSocketHandler(hub *pws.Hub, firebaseAuth *config.FirebaseAuth) *WebSo // @Tags Chat // @Accept json // @Produce json -// @Security BearerAuth -// @Success 101 {string} string "Switching Protocols a WebSocket" -// @Failure 401 {string} string "No autorizado" +// @Param token query string true "Firebase Auth Token" +// @Success 101 {string} string "Switching Protocols a WebSocket" +// @Failure 401 {string} string "No autorizado" // @Router /chat/ws [get] func (h *WebSocketHandler) HandleWebSocket(w http.ResponseWriter, r *http.Request) { - // Verificar el token desde el contexto (añadido por el middleware de autenticación) - userID, ok := r.Context().Value("userID").(string) - if !ok { - http.Error(w, "Unauthorized", http.StatusUnauthorized) + // Extraer el token desde el parámetro de consulta + token := r.URL.Query().Get("token") + if token == "" { + http.Error(w, "Token not provided", http.StatusUnauthorized) + return + } + + // Limpiar el token (por si viene con "Bearer ") + token = strings.TrimPrefix(token, "Bearer ") + + // Verificar el token con Firebase + authToken, err := h.firebaseAuth.VerifyIDToken(r.Context(), token) + if err != nil { + log.Printf("Error verifying token: %v", err) + http.Error(w, "Invalid token", http.StatusUnauthorized) + return + } + + // Extraer el userID del token verificado + userID := authToken.UID + if userID == "" { + http.Error(w, "Invalid user ID in token", http.StatusUnauthorized) return } diff --git a/internal/routes/router.go b/internal/routes/router.go index 8b816d1..1033a10 100644 --- a/internal/routes/router.go +++ b/internal/routes/router.go @@ -56,28 +56,29 @@ func NewRouter( // Rutas de chat (protegidas) r.Route("/chat", func(r chi.Router) { - // Aplicar middleware de autenticación - r.Use(authMw.VerifyToken) + // WebSocket endpoint + r.Get("/ws", webSocketHandler.HandleWebSocket) - // Rutas de salas - r.Route("/rooms", func(r chi.Router) { - r.Post("/", chatHandler.CreateRoom) - r.Get("/me", chatHandler.GetUserRooms) - r.Get("/", chatHandler.GetAllRooms) - r.Get("/{roomId}", chatHandler.GetRoom) - r.Get("/{roomId}/messages", chatHandler.GetRoomMessages) - r.Post("/{roomId}/join", chatHandler.JoinRoom) - }) + r.Group(func(r chi.Router) { + r.Use(authMw.VerifyToken) // Aplicar middleware de autenticación - // Rutas de chats directos - r.Route("/direct", func(r chi.Router) { - r.Post("/{otherUserId}", chatHandler.CreateDirectChat) - r.Get("/me", chatHandler.GetUserDirectChats) - r.Get("/{chatId}/messages", chatHandler.GetDirectChatMessages) - }) + // Rutas de salas + r.Route("/rooms", func(r chi.Router) { + r.Post("/", chatHandler.CreateRoom) + r.Get("/me", chatHandler.GetUserRooms) + r.Get("/", chatHandler.GetAllRooms) + r.Get("/{roomId}", chatHandler.GetRoom) + r.Get("/{roomId}/messages", chatHandler.GetRoomMessages) + r.Post("/{roomId}/join", chatHandler.JoinRoom) + }) - // WebSocket endpoint - r.Get("/ws", webSocketHandler.HandleWebSocket) + // Rutas de chats directos + r.Route("/direct", func(r chi.Router) { + r.Post("/{otherUserId}", chatHandler.CreateDirectChat) + r.Get("/me", chatHandler.GetUserDirectChats) + r.Get("/{chatId}/messages", chatHandler.GetDirectChatMessages) + }) + }) }) })