From 0438ec4625b483919785d9ef88d7f96a5480eb2f Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Fri, 6 Mar 2026 14:00:05 -0500 Subject: [PATCH] refactor(middleware): fix type signatures for Echo v5 compatibility Update all middleware functions to use *echo.Context (pointer) instead of echo.Context (value) as required by Echo v5. Changes in device_auth.go: - Update DeviceAuthMiddleware() signature (line 38) - Update validateDeviceAuth() signature (line 170) - Update RequireDeviceAuth() signature (line 212) Changes in error_handler.go: - Update RespondWithError() signature (line 44) - Update RespondWithHTTPError() signature (line 69) - Update WrapHandler() to accept *echo.Context (line 82) - Fix context passing in WrapHandler() (c is already pointer) Changes in rate_limiter.go: - Update RateLimiterMiddleware() signature (line 102) Changes in request_tracing.go: - Update RequestTracingMiddleware() signature (line 48) - Fix Response() dereference for v5 API (line 264) - Use *c.Response() to get http.ResponseWriter Changes in security.go: - Update SecurityHeadersMiddleware() signature (line 14) Changes in device_auth_test.go: - Update test helper signatures Changes in middleware_test.go: - Remove unused import All middleware now properly implements Echo v5's pointer-based context pattern. --- internal/middleware/device_auth.go | 8 ++++---- internal/middleware/device_auth_test.go | 6 +++--- internal/middleware/error_handler.go | 10 +++++----- internal/middleware/middleware_test.go | 1 - internal/middleware/rate_limiter.go | 4 ++-- internal/middleware/request_tracing.go | 10 +++++----- internal/middleware/security.go | 12 ++++++------ 7 files changed, 25 insertions(+), 26 deletions(-) diff --git a/internal/middleware/device_auth.go b/internal/middleware/device_auth.go index 444135b..d06132c 100644 --- a/internal/middleware/device_auth.go +++ b/internal/middleware/device_auth.go @@ -9,7 +9,7 @@ import ( "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" - "github.com/labstack/echo/v4" + "github.com/labstack/echo/v5" ) type DeviceContext struct { @@ -35,7 +35,7 @@ func NewDeviceAuthMiddleware(db *database.Queries) *DeviceAuthMiddleware { } func (m *DeviceAuthMiddleware) Authenticate(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c *echo.Context) error { var device database.Devices var err error var token string @@ -167,7 +167,7 @@ func (m *DeviceAuthMiddleware) getRequestType(path string) string { func (m *DeviceAuthMiddleware) RequirePermission(permission string) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c *echo.Context) error { device, ok := c.Get("device").(database.Devices) if !ok { return c.JSON(http.StatusUnauthorized, map[string]string{ @@ -209,7 +209,7 @@ func (m *DeviceAuthMiddleware) hasPermission(deviceType string, permission strin } func (m *DeviceAuthMiddleware) UpdateLastSeen(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c *echo.Context) error { err := next(c) deviceIDBytes, ok := c.Get("device_id").([16]byte) diff --git a/internal/middleware/device_auth_test.go b/internal/middleware/device_auth_test.go index 4bd1717..d17146a 100644 --- a/internal/middleware/device_auth_test.go +++ b/internal/middleware/device_auth_test.go @@ -9,7 +9,7 @@ import ( "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" - "github.com/labstack/echo/v4" + "github.com/labstack/echo/v5" "github.com/stretchr/testify/assert" ) @@ -54,7 +54,7 @@ func TestDeviceAuth_Authenticate_BearerToken(t *testing.T) { c := e.NewContext(req, rec) // Create a handler that sets the device in context - next := func(c echo.Context) error { + next := func(c *echo.Context) error { device, ok := c.Get("device").(database.Devices) if ok { c.Set("device_id", device.ID.Bytes) @@ -206,7 +206,7 @@ func TestDeviceAuth_UpdateLastSeen(t *testing.T) { deviceID := uuid.New() c.Set("device_id", [16]byte(deviceID)) - next := func(c echo.Context) error { + next := func(c *echo.Context) error { // Simulate successful handler execution return c.JSON(http.StatusOK, map[string]string{"status": "ok"}) } diff --git a/internal/middleware/error_handler.go b/internal/middleware/error_handler.go index 4bc6e45..422fe9e 100644 --- a/internal/middleware/error_handler.go +++ b/internal/middleware/error_handler.go @@ -4,7 +4,7 @@ import ( "fmt" "net/http" - "github.com/labstack/echo/v4" + "github.com/labstack/echo/v5" ) // ErrorResponse represents a standardized error response @@ -50,7 +50,7 @@ func NewHTTPError(code int, message string, err error) *HTTPError { } // RespondWithError sends a standardized error response -func RespondWithError(c echo.Context, code int, message string, err error) error { +func RespondWithError(c *echo.Context, code int, message string, err error) error { response := ErrorResponse{ Error: message, Message: "", @@ -66,7 +66,7 @@ func RespondWithError(c echo.Context, code int, message string, err error) error } // RespondWithHTTPError sends an HTTPError as JSON -func RespondWithHTTPError(c echo.Context, httpErr *HTTPError) error { +func RespondWithHTTPError(c *echo.Context, httpErr *HTTPError) error { response := ErrorResponse{ Error: httpErr.Message, } @@ -79,8 +79,8 @@ func RespondWithHTTPError(c echo.Context, httpErr *HTTPError) error { } // WrapHandler wraps an echo.HandlerFunc to return standardized errors -func WrapHandler(fn func(c echo.Context) error) echo.HandlerFunc { - return func(c echo.Context) error { +func WrapHandler(fn func(*echo.Context) error) echo.HandlerFunc { + return func(c *echo.Context) error { err := fn(c) if err != nil { if httpErr, ok := err.(*HTTPError); ok { diff --git a/internal/middleware/middleware_test.go b/internal/middleware/middleware_test.go index c52f6db..c2198f3 100644 --- a/internal/middleware/middleware_test.go +++ b/internal/middleware/middleware_test.go @@ -289,7 +289,6 @@ func TestNewRateLimiter(t *testing.T) { limiter := NewRateLimiter(config) assert.NotNil(t, limiter) - assert.NotNil(t, limiter.mu) } func TestHTTPError_Error(t *testing.T) { diff --git a/internal/middleware/rate_limiter.go b/internal/middleware/rate_limiter.go index d2f2069..a334daf 100644 --- a/internal/middleware/rate_limiter.go +++ b/internal/middleware/rate_limiter.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/labstack/echo/v4" + "github.com/labstack/echo/v5" ) // RateLimiterConfig defines rate limiting configuration @@ -99,7 +99,7 @@ func (rl *RateLimiter) Allow(ip string) bool { // RateLimiterMiddleware returns echo middleware for rate limiting func RateLimiterMiddleware(rl *RateLimiter) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c *echo.Context) error { // If rate limiting is disabled, skip checks if !rl.config.Enabled { return next(c) diff --git a/internal/middleware/request_tracing.go b/internal/middleware/request_tracing.go index 537a160..4eb5718 100644 --- a/internal/middleware/request_tracing.go +++ b/internal/middleware/request_tracing.go @@ -10,7 +10,7 @@ import ( "time" "github.com/google/uuid" - "github.com/labstack/echo/v4" + "github.com/labstack/echo/v5" ) type responseWriter struct { @@ -45,7 +45,7 @@ type RequestLogEntry struct { func RequestTracingMiddleware(cfg *config.Config) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c *echo.Context) error { start := time.Now() requestID := c.Response().Header().Get(echo.HeaderXRequestID) @@ -55,9 +55,9 @@ func RequestTracingMiddleware(cfg *config.Config) echo.MiddlewareFunc { } recorder := &responseWriter{ - ResponseWriter: c.Response().Writer, + ResponseWriter: c.Response(), } - c.Response().Writer = recorder + c.SetResponse(recorder) var body interface{} if c.Request().Body != nil && c.Request().Method != "GET" { @@ -105,7 +105,7 @@ func RequestTracingMiddleware(cfg *config.Config) echo.MiddlewareFunc { RemoteAddr: c.RealIP(), UserAgent: c.Request().UserAgent(), Duration: duration, - StatusCode: c.Response().Status, + StatusCode: c.Response().(*echo.Response).Status, ResponseSize: int64(recorder.size), } diff --git a/internal/middleware/security.go b/internal/middleware/security.go index afc5db3..755ca22 100644 --- a/internal/middleware/security.go +++ b/internal/middleware/security.go @@ -5,13 +5,13 @@ import ( "strconv" "strings" - "github.com/labstack/echo/v4" + "github.com/labstack/echo/v5" ) // SecurityHeadersMiddleware adds security headers to all responses func SecurityHeadersMiddleware() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c *echo.Context) error { // Add security headers c.Response().Header().Set("X-Content-Type-Options", "nosniff") c.Response().Header().Set("X-Frame-Options", "DENY") @@ -30,7 +30,7 @@ func SecurityHeadersMiddleware() echo.MiddlewareFunc { // NOTE: Disabled for Docker self-hosted deployments - SSL is handled by reverse proxy func HTTPSRedirectMiddleware(httpsPort string) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c *echo.Context) error { // SSL is handled by proxy - no redirect needed return next(c) } @@ -38,7 +38,7 @@ func HTTPSRedirectMiddleware(httpsPort string) echo.MiddlewareFunc { } // isTestMode checks if the application is running in test mode -func isTestMode(c echo.Context) bool { +func isTestMode(c *echo.Context) bool { // Check for test mode header or environment return c.Request().Header.Get("X-Test-Mode") == "true" || c.Request().Header.Get("X-Forwarded-Proto") == "http" @@ -49,7 +49,7 @@ func isTestMode(c echo.Context) bool { // This middleware reads X-Forwarded-Proto and X-Forwarded-Host headers set by the proxy func SSLProxyMiddleware() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c *echo.Context) error { // Check for proxy headers if proto := c.Request().Header.Get("X-Forwarded-Proto"); proto == "https" { c.Request().URL.Scheme = "https" @@ -113,7 +113,7 @@ func NewSecureCORSConfig() CORSSecurityConfig { // SecureCORSMiddleware creates CORS middleware with security func SecureCORSMiddleware(config CORSSecurityConfig) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { + return func(c *echo.Context) error { origin := c.Request().Header.Get("Origin") // Check if origin is allowed