diff --git a/internal/router/analytics.go b/internal/router/analytics.go index f464ab2..1c34136 100644 --- a/internal/router/analytics.go +++ b/internal/router/analytics.go @@ -1,17 +1,10 @@ package router -import ( - "github.com/labstack/echo-jwt/v4" -) - func registerAnalyticsRoutes(cfg *Config) { e := cfg.Echo // JWT middleware for protected routes - jwtMiddleware := echojwt.WithConfig(echojwt.Config{ - SigningKey: []byte(cfg.Cfg.JWTSecret), - ContextKey: "user", - }) + jwtMiddleware := createJWTMiddleware(cfg) protected := e.Group("/api", jwtMiddleware) diff --git a/internal/router/auth.go b/internal/router/auth.go index fdc7649..3fe1a9d 100644 --- a/internal/router/auth.go +++ b/internal/router/auth.go @@ -3,8 +3,6 @@ package router import ( "bookhoard/internal/handlers" - "github.com/golang-jwt/jwt/v5" - "github.com/labstack/echo-jwt/v4" "github.com/labstack/echo/v4" ) @@ -16,18 +14,7 @@ func registerAuthRoutes(cfg *Config, rateLimitMiddleware echo.MiddlewareFunc) { e.POST("/api/auth/login", rateLimitMiddleware(cfg.AuthHandler.Login)) // JWT middleware for protected routes - jwtMiddleware := echojwt.WithConfig(echojwt.Config{ - SigningKey: []byte(cfg.Cfg.JWTSecret), - ContextKey: "user", - SuccessHandler: func(c echo.Context) { - token := c.Get("user").(*jwt.Token) - claims := token.Claims.(jwt.MapClaims) - c.Set("user_id", claims["user_id"]) - c.Set("user_role", claims["user_role"]) - c.Set("user_email", claims["user_email"]) - c.Set("user_username", claims["user_username"]) - }, - }) + jwtMiddleware := createJWTMiddleware(cfg) // Create protected route group protected := e.Group("/api", jwtMiddleware) @@ -43,7 +30,7 @@ func registerAuthRoutes(cfg *Config, rateLimitMiddleware echo.MiddlewareFunc) { e.POST("/api/auth/logout", cfg.AuthHandler.Logout) // Auth update routes - authGroup := e.Group("/api/auth", jwtMiddleware) + authGroup := e.Group("/api/auth", createJWTMiddleware(cfg)) authGroup.PUT("/email", cfg.AuthHandler.UpdateEmail) authGroup.PUT("/username", cfg.AuthHandler.UpdateUsername) authGroup.PUT("/password", cfg.AuthHandler.UpdatePassword) diff --git a/internal/router/conflicts.go b/internal/router/conflicts.go index d873696..27976e4 100644 --- a/internal/router/conflicts.go +++ b/internal/router/conflicts.go @@ -1,17 +1,10 @@ package router -import ( - "github.com/labstack/echo-jwt/v4" -) - func registerConflictRoutes(cfg *Config) { e := cfg.Echo // JWT middleware for protected routes - jwtMiddleware := echojwt.WithConfig(echojwt.Config{ - SigningKey: []byte(cfg.Cfg.JWTSecret), - ContextKey: "user", - }) + jwtMiddleware := createJWTMiddleware(cfg) protected := e.Group("/api", jwtMiddleware) diff --git a/internal/router/device.go b/internal/router/device.go index 46e5ad8..c8ed8c1 100644 --- a/internal/router/device.go +++ b/internal/router/device.go @@ -1,27 +1,10 @@ package router -import ( - "github.com/golang-jwt/jwt/v5" - "github.com/labstack/echo-jwt/v4" - "github.com/labstack/echo/v4" -) - func registerDeviceRoutes(cfg *Config) { e := cfg.Echo // JWT middleware - jwtMiddleware := echojwt.WithConfig(echojwt.Config{ - SigningKey: []byte(cfg.Cfg.JWTSecret), - ContextKey: "user", - SuccessHandler: func(c echo.Context) { - token := c.Get("user").(*jwt.Token) - claims := token.Claims.(jwt.MapClaims) - c.Set("user_id", claims["user_id"]) - c.Set("user_role", claims["user_role"]) - c.Set("user_email", claims["user_email"]) - c.Set("user_username", claims["user_username"]) - }, - }) + jwtMiddleware := createJWTMiddleware(cfg) // Protected routes protected := e.Group("/api", jwtMiddleware) diff --git a/internal/router/media.go b/internal/router/media.go index 56538f9..0725010 100644 --- a/internal/router/media.go +++ b/internal/router/media.go @@ -2,18 +2,13 @@ package router import ( "bookhoard/internal/handlers" - - "github.com/labstack/echo-jwt/v4" ) func registerMediaRoutes(cfg *Config) { e := cfg.Echo // JWT middleware for protected routes - jwtMiddleware := echojwt.WithConfig(echojwt.Config{ - SigningKey: []byte(cfg.Cfg.JWTSecret), - ContextKey: "user", - }) + jwtMiddleware := createJWTMiddleware(cfg) protected := e.Group("/api", jwtMiddleware) diff --git a/internal/router/queue.go b/internal/router/queue.go index bad9b8d..18e9080 100644 --- a/internal/router/queue.go +++ b/internal/router/queue.go @@ -1,7 +1,6 @@ package router import ( - "github.com/labstack/echo-jwt/v4" "github.com/labstack/echo/v4" ) @@ -9,10 +8,7 @@ func registerQueueRoutes(cfg *Config) { e := cfg.Echo // JWT middleware for protected routes - jwtMiddleware := echojwt.WithConfig(echojwt.Config{ - SigningKey: []byte(cfg.Cfg.JWTSecret), - ContextKey: "user", - }) + jwtMiddleware := createJWTMiddleware(cfg) protected := e.Group("/api", jwtMiddleware) diff --git a/internal/router/router.go b/internal/router/router.go index 4cb10ee..2fe6296 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -8,9 +8,14 @@ import ( ratelimit "bookhoard/internal/middleware" "bookhoard/internal/sync" "log" + "net/http" "time" "github.com/go-playground/validator/v10" + "github.com/golang-jwt/jwt/v5" + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" + "github.com/labstack/echo-jwt/v4" "github.com/labstack/echo/v4" echomiddleware "github.com/labstack/echo/v4/middleware" ) @@ -46,6 +51,37 @@ type Config struct { LoginTracker *ratelimit.LoginAttemptTracker } +// createJWTMiddleware creates a JWT middleware with proper user context setup +func createJWTMiddleware(cfg *Config) echo.MiddlewareFunc { + return echojwt.WithConfig(echojwt.Config{ + SigningKey: []byte(cfg.Cfg.JWTSecret), + ContextKey: "user", + SuccessHandler: func(c echo.Context) { + token := c.Get("user").(*jwt.Token) + claims := token.Claims.(jwt.MapClaims) + c.Set("user_id", claims["user_id"]) + c.Set("user_role", claims["user_role"]) + c.Set("user_email", claims["user_email"]) + c.Set("user_username", claims["user_username"]) + + // Parse UUID from string claims + userIDStr, _ := claims["user_id"].(string) + userUUID, err := uuid.Parse(userIDStr) + if err != nil { + c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid user ID in token"}) + return + } + + c.Set("user", database.Users{ + ID: pgtype.UUID{Bytes: [16]byte(userUUID), Valid: true}, + Email: claims["user_email"].(string), + Username: claims["user_username"].(string), + Role: claims["user_role"].(string), + }) + }, + }) +} + // RegisterRoutes registers all application routes func RegisterRoutes(cfg *Config) { e := cfg.Echo diff --git a/internal/router/sync.go b/internal/router/sync.go index b8dcc38..1a26a37 100644 --- a/internal/router/sync.go +++ b/internal/router/sync.go @@ -2,28 +2,13 @@ package router import ( "bookhoard/internal/handlers" - - "github.com/golang-jwt/jwt/v5" - "github.com/labstack/echo-jwt/v4" - "github.com/labstack/echo/v4" ) func registerSyncRoutes(cfg *Config) { e := cfg.Echo // JWT middleware for protected routes - jwtMiddleware := echojwt.WithConfig(echojwt.Config{ - SigningKey: []byte(cfg.Cfg.JWTSecret), - ContextKey: "user", - SuccessHandler: func(c echo.Context) { - token := c.Get("user").(*jwt.Token) - claims := token.Claims.(jwt.MapClaims) - c.Set("user_id", claims["user_id"]) - c.Set("user_role", claims["user_role"]) - c.Set("user_email", claims["user_email"]) - c.Set("user_username", claims["user_username"]) - }, - }) + jwtMiddleware := createJWTMiddleware(cfg) protected := e.Group("/api", jwtMiddleware)