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.
This commit is contained in:
2026-03-06 14:00:05 -05:00
parent abb090ef64
commit 0438ec4625
7 changed files with 25 additions and 26 deletions
+4 -4
View File
@@ -9,7 +9,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type DeviceContext struct { type DeviceContext struct {
@@ -35,7 +35,7 @@ func NewDeviceAuthMiddleware(db *database.Queries) *DeviceAuthMiddleware {
} }
func (m *DeviceAuthMiddleware) Authenticate(next echo.HandlerFunc) echo.HandlerFunc { 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 device database.Devices
var err error var err error
var token string var token string
@@ -167,7 +167,7 @@ func (m *DeviceAuthMiddleware) getRequestType(path string) string {
func (m *DeviceAuthMiddleware) RequirePermission(permission string) echo.MiddlewareFunc { func (m *DeviceAuthMiddleware) RequirePermission(permission string) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc { 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) device, ok := c.Get("device").(database.Devices)
if !ok { if !ok {
return c.JSON(http.StatusUnauthorized, map[string]string{ 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 { func (m *DeviceAuthMiddleware) UpdateLastSeen(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error { return func(c *echo.Context) error {
err := next(c) err := next(c)
deviceIDBytes, ok := c.Get("device_id").([16]byte) deviceIDBytes, ok := c.Get("device_id").([16]byte)
+3 -3
View File
@@ -9,7 +9,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -54,7 +54,7 @@ func TestDeviceAuth_Authenticate_BearerToken(t *testing.T) {
c := e.NewContext(req, rec) c := e.NewContext(req, rec)
// Create a handler that sets the device in context // 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) device, ok := c.Get("device").(database.Devices)
if ok { if ok {
c.Set("device_id", device.ID.Bytes) c.Set("device_id", device.ID.Bytes)
@@ -206,7 +206,7 @@ func TestDeviceAuth_UpdateLastSeen(t *testing.T) {
deviceID := uuid.New() deviceID := uuid.New()
c.Set("device_id", [16]byte(deviceID)) c.Set("device_id", [16]byte(deviceID))
next := func(c echo.Context) error { next := func(c *echo.Context) error {
// Simulate successful handler execution // Simulate successful handler execution
return c.JSON(http.StatusOK, map[string]string{"status": "ok"}) return c.JSON(http.StatusOK, map[string]string{"status": "ok"})
} }
+5 -5
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
// ErrorResponse represents a standardized error response // 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 // 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{ response := ErrorResponse{
Error: message, Error: message,
Message: "", Message: "",
@@ -66,7 +66,7 @@ func RespondWithError(c echo.Context, code int, message string, err error) error
} }
// RespondWithHTTPError sends an HTTPError as JSON // RespondWithHTTPError sends an HTTPError as JSON
func RespondWithHTTPError(c echo.Context, httpErr *HTTPError) error { func RespondWithHTTPError(c *echo.Context, httpErr *HTTPError) error {
response := ErrorResponse{ response := ErrorResponse{
Error: httpErr.Message, Error: httpErr.Message,
} }
@@ -79,8 +79,8 @@ func RespondWithHTTPError(c echo.Context, httpErr *HTTPError) error {
} }
// WrapHandler wraps an echo.HandlerFunc to return standardized errors // WrapHandler wraps an echo.HandlerFunc to return standardized errors
func WrapHandler(fn func(c echo.Context) error) echo.HandlerFunc { func WrapHandler(fn func(*echo.Context) error) echo.HandlerFunc {
return func(c echo.Context) error { return func(c *echo.Context) error {
err := fn(c) err := fn(c)
if err != nil { if err != nil {
if httpErr, ok := err.(*HTTPError); ok { if httpErr, ok := err.(*HTTPError); ok {
-1
View File
@@ -289,7 +289,6 @@ func TestNewRateLimiter(t *testing.T) {
limiter := NewRateLimiter(config) limiter := NewRateLimiter(config)
assert.NotNil(t, limiter) assert.NotNil(t, limiter)
assert.NotNil(t, limiter.mu)
} }
func TestHTTPError_Error(t *testing.T) { func TestHTTPError_Error(t *testing.T) {
+2 -2
View File
@@ -5,7 +5,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
// RateLimiterConfig defines rate limiting configuration // RateLimiterConfig defines rate limiting configuration
@@ -99,7 +99,7 @@ func (rl *RateLimiter) Allow(ip string) bool {
// RateLimiterMiddleware returns echo middleware for rate limiting // RateLimiterMiddleware returns echo middleware for rate limiting
func RateLimiterMiddleware(rl *RateLimiter) echo.MiddlewareFunc { func RateLimiterMiddleware(rl *RateLimiter) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc { 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 rate limiting is disabled, skip checks
if !rl.config.Enabled { if !rl.config.Enabled {
return next(c) return next(c)
+5 -5
View File
@@ -10,7 +10,7 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type responseWriter struct { type responseWriter struct {
@@ -45,7 +45,7 @@ type RequestLogEntry struct {
func RequestTracingMiddleware(cfg *config.Config) echo.MiddlewareFunc { func RequestTracingMiddleware(cfg *config.Config) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc { return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error { return func(c *echo.Context) error {
start := time.Now() start := time.Now()
requestID := c.Response().Header().Get(echo.HeaderXRequestID) requestID := c.Response().Header().Get(echo.HeaderXRequestID)
@@ -55,9 +55,9 @@ func RequestTracingMiddleware(cfg *config.Config) echo.MiddlewareFunc {
} }
recorder := &responseWriter{ recorder := &responseWriter{
ResponseWriter: c.Response().Writer, ResponseWriter: c.Response(),
} }
c.Response().Writer = recorder c.SetResponse(recorder)
var body interface{} var body interface{}
if c.Request().Body != nil && c.Request().Method != "GET" { if c.Request().Body != nil && c.Request().Method != "GET" {
@@ -105,7 +105,7 @@ func RequestTracingMiddleware(cfg *config.Config) echo.MiddlewareFunc {
RemoteAddr: c.RealIP(), RemoteAddr: c.RealIP(),
UserAgent: c.Request().UserAgent(), UserAgent: c.Request().UserAgent(),
Duration: duration, Duration: duration,
StatusCode: c.Response().Status, StatusCode: c.Response().(*echo.Response).Status,
ResponseSize: int64(recorder.size), ResponseSize: int64(recorder.size),
} }
+6 -6
View File
@@ -5,13 +5,13 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
// SecurityHeadersMiddleware adds security headers to all responses // SecurityHeadersMiddleware adds security headers to all responses
func SecurityHeadersMiddleware() echo.MiddlewareFunc { func SecurityHeadersMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc { return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error { return func(c *echo.Context) error {
// Add security headers // Add security headers
c.Response().Header().Set("X-Content-Type-Options", "nosniff") c.Response().Header().Set("X-Content-Type-Options", "nosniff")
c.Response().Header().Set("X-Frame-Options", "DENY") 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 // NOTE: Disabled for Docker self-hosted deployments - SSL is handled by reverse proxy
func HTTPSRedirectMiddleware(httpsPort string) echo.MiddlewareFunc { func HTTPSRedirectMiddleware(httpsPort string) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc { 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 // SSL is handled by proxy - no redirect needed
return next(c) return next(c)
} }
@@ -38,7 +38,7 @@ func HTTPSRedirectMiddleware(httpsPort string) echo.MiddlewareFunc {
} }
// isTestMode checks if the application is running in test mode // 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 // Check for test mode header or environment
return c.Request().Header.Get("X-Test-Mode") == "true" || return c.Request().Header.Get("X-Test-Mode") == "true" ||
c.Request().Header.Get("X-Forwarded-Proto") == "http" 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 // This middleware reads X-Forwarded-Proto and X-Forwarded-Host headers set by the proxy
func SSLProxyMiddleware() echo.MiddlewareFunc { func SSLProxyMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc { return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error { return func(c *echo.Context) error {
// Check for proxy headers // Check for proxy headers
if proto := c.Request().Header.Get("X-Forwarded-Proto"); proto == "https" { if proto := c.Request().Header.Get("X-Forwarded-Proto"); proto == "https" {
c.Request().URL.Scheme = "https" c.Request().URL.Scheme = "https"
@@ -113,7 +113,7 @@ func NewSecureCORSConfig() CORSSecurityConfig {
// SecureCORSMiddleware creates CORS middleware with security // SecureCORSMiddleware creates CORS middleware with security
func SecureCORSMiddleware(config CORSSecurityConfig) echo.MiddlewareFunc { func SecureCORSMiddleware(config CORSSecurityConfig) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc { 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") origin := c.Request().Header.Get("Origin")
// Check if origin is allowed // Check if origin is allowed