From f72b4817208b5c45ce23808eadfb688fb0937779 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Sun, 4 Oct 2026 00:50:37 +0100 Subject: [PATCH] chore(deps): migrate fiber from v2 to v3 The automated update changed only go.mod, so the build failed on the old v2 imports. This commit moves the code to the v3 API. The commit replaces BodyParser with Bind().Body, Static with the static middleware, and ListenTLS with ListenConfig. It also updates the tests for TestConfig. Fixes #179 --- go.mod | 10 ++-- go.sum | 22 +++++--- pkg/app/app.go | 12 +++-- pkg/app/handlers.go | 16 +++--- pkg/app/handlers_admin.go | 20 +++---- pkg/app/handlers_analytics.go | 16 +++--- pkg/app/handlers_analytics_test.go | 2 +- pkg/app/handlers_auth.go | 10 ++-- pkg/app/handlers_auth_test.go | 19 +++---- pkg/app/handlers_prewarming.go | 10 ++-- pkg/app/handlers_prewarming_test.go | 2 +- pkg/app/handlers_vulnerabilities.go | 4 +- pkg/app/middleware.go | 18 +++---- pkg/app/middleware_test.go | 82 ++++++++++++++--------------- 14 files changed, 127 insertions(+), 116 deletions(-) diff --git a/go.mod b/go.mod index fb907c3..23c9ec3 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/go-gormigrate/gormigrate/v2 v2.1.7 github.com/go-sql-driver/mysql v1.10.1 github.com/goccy/go-json v0.11.2 - github.com/gofiber/fiber/v2 v2.52.15 github.com/gofiber/fiber/v3 v3.5.0 github.com/gorilla/websocket v1.5.3 github.com/lib/pq v1.12.3 @@ -52,10 +51,8 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.51.1 // indirect github.com/aws/smithy-go v1.28.2 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v7 v7.0.1 // indirect - github.com/cenkalti/backoff/v7 v7.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/cloudsoda/sddl v0.0.0-20250224235906-926454e91efc // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect @@ -73,6 +70,8 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect + github.com/gofiber/schema v1.8.3 // indirect + github.com/gofiber/utils/v2 v2.4.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-uuid v1.0.4 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -93,7 +92,6 @@ require ( github.com/magiconair/properties v1.18.12 // indirect github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.24 // indirect - github.com/mattn/go-runewidth v0.0.30 // indirect github.com/mattn/go-sqlite3 v1.14.52 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/go-archive v0.3.3 // indirect @@ -109,6 +107,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pelletier/go-toml/v2 v2.4.3 // indirect + github.com/philhofer/fwd v1.2.0 // indirect github.com/power-devops/perfstat v0.0.0-20260916203055-22a1a467d9f0 // indirect github.com/prometheus/client_model v0.6.3 // indirect github.com/prometheus/common v0.72.0 // indirect @@ -121,6 +120,7 @@ require ( github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/objx v0.5.3 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/tinylib/msgp v1.6.4 // indirect github.com/tklauser/go-sysconf v0.4.0 // indirect github.com/tklauser/numcpus v0.12.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect diff --git a/go.sum b/go.sum index 42ddad9..84f359b 100644 --- a/go.sum +++ b/go.sum @@ -48,11 +48,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cenkalti/backoff/v7 v7.0.1/go.mod h1:qcKBGwsu4hpxHtQ8tWYsQ+ifzx2+sS+Xx/3jfe30lI8= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= -github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/cloudsoda/go-smb2 v0.0.0-20260918041005-0c5d69b69701 h1:xiTow1n7oNJPzn9QH+U2sT65mO2F12zNNlY4ZzOew70= github.com/cloudsoda/go-smb2 v0.0.0-20260918041005-0c5d69b69701/go.mod h1:1pQXB0vAlzRlqcY7LYKOOZMw0wKfJPFxTLsJRF2Gswo= github.com/cloudsoda/sddl v0.0.0-20250224235906-926454e91efc h1:0xCWmFKBmarCqqqLeM7jFBSw/Or81UEElFqO8MY+GDs= @@ -86,6 +83,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= +github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78= +github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/geoffgarside/ber v1.2.0 h1:/loowoRcs/MWLYmGX9QtIAbA+V/FrnVLsMMPhwiRm64= github.com/geoffgarside/ber v1.2.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc= github.com/go-gormigrate/gormigrate/v2 v2.1.7 h1:PdT4jVPbRb4R+0Ey2R0yJOdctVf4Whiq1Qi4necaZdg= @@ -104,9 +103,12 @@ github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPE github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.11.2 h1:jdZv93Tt4ioR8yW1CoNsvSxrcZlCXAUU1aZXN7gpXUA= github.com/goccy/go-json v0.11.2/go.mod h1:3NdmfEkZlB7YI5UFw/qdFKq8XN1aiWR0YyRPWZNQltY= -github.com/gofiber/fiber/v2 v2.52.15 h1:Cov1uKeVPyu9q0jSrN60W+A8XNX+/WK8J7cy5osHLIk= -github.com/gofiber/fiber/v2 v2.52.15/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/fiber/v3 v3.5.0 h1:dk7TOUH6DXJGtOLsN2XEG+0ZML7cznzHILTVozbNEK8= github.com/gofiber/fiber/v3 v3.5.0/go.mod h1:GOVDTW+gjJvfe0iJyVujbQ1Lnx+JUjFySJRI/9/xX/w= +github.com/gofiber/schema v1.8.3 h1:06ZedxIYjngzc0095PYy7uWnFnbRflWFpikvZH61fDc= +github.com/gofiber/schema v1.8.3/go.mod h1:jWnnZdhcW1mHyV+VnfRxKJDPNcepJsTZ9RIWxrr32Ng= +github.com/gofiber/utils/v2 v2.4.1 h1:E2X9G8O5Mn7b2GDb0JU3IUk42Rw2npuhhepIbuJQ2po= +github.com/gofiber/utils/v2 v2.4.1/go.mod h1:I+RTsgMUdzFuifVc3LOEkfh32wQW9BfRl7l5RYjamW4= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -165,8 +167,6 @@ github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= -github.com/mattn/go-runewidth v0.0.30 h1:+KUuiDA4fF0R1p5FeueHefjDm+GIM+kWfFnDjybOPgk= -github.com/mattn/go-runewidth v0.0.30/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8= github.com/mattn/go-sqlite3 v1.14.52 h1:wVbm2Qnf4OXkqhBTSPuCRZDRnxfbVrrmiCEroVdog8U= github.com/mattn/go-sqlite3 v1.14.52/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w= github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= @@ -203,6 +203,8 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY= github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20260916203055-22a1a467d9f0 h1:XA01Vk/wv9YikCi1V51yRzIHPMT5of9+cMpZoZvDn/M= github.com/power-devops/perfstat v0.0.0-20260916203055-22a1a467d9f0/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= @@ -221,6 +223,8 @@ github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= +github.com/shamaton/msgpack/v3 v3.2.0 h1:1q2Ms+MWmuRju+PuDMSFDB7p7621npeX4zprJN5Zck8= +github.com/shamaton/msgpack/v3 v3.2.0/go.mod h1:sgBYvEiyz8JR1NC3yGRoPVME9xXovpnh3l/plW1nfRo= github.com/shirou/gopsutil/v4 v4.26.9 h1:CaBo/hBFqvlJoLvAQEKdHdf5GD97/MN2ACfyv63+2Ig= github.com/shirou/gopsutil/v4 v4.26.9/go.mod h1:nKH+8wX2zxr/mDbsR+AAy6Qd2z4ZOQ7wfQaEp+yrYmg= github.com/sirupsen/logrus v1.10.2 h1:G2SED73/qrAu6YwbdxOD6peLkCBI3z7L+ykJFTXJBBo= @@ -257,6 +261,8 @@ github.com/testcontainers/testcontainers-go/modules/mysql v0.44.0 h1:oJPJPxNE6YQ github.com/testcontainers/testcontainers-go/modules/mysql v0.44.0/go.mod h1:MSOAU6ukCpehJVHQDN1k9JgOZXZuqHD+2pT20M3JkIg= github.com/testcontainers/testcontainers-go/modules/postgres v0.44.0 h1:8fdv/9y3JMxjQ+ULAcOG8RtgeNu5t9XF9LolSXDuTwM= github.com/testcontainers/testcontainers-go/modules/postgres v0.44.0/go.mod h1:CFr2LncGYokw+OKjXcr8ARCKG1SaC2UEnGxFBovE86g= +github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ= +github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU= github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI= github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4= @@ -265,6 +271,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.74.0 h1:wMS9fnO2QTALozYx5pId2Vi7ZwU/epUkY8i/KPWCHoU= github.com/valyala/fasthttp v1.74.0/go.mod h1:3ARmLamUcw7ElxVtC8PXaGzQ6VEuvnetlkrwIklQBSE= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= diff --git a/pkg/app/app.go b/pkg/app/app.go index dac62fa..6dea084 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -15,8 +15,9 @@ import ( "syscall" "time" - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/middleware/adaptor" + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/adaptor" + "github.com/gofiber/fiber/v3/middleware/static" "github.com/lukaszraczylo/gohoarder/pkg/analytics" "github.com/lukaszraczylo/gohoarder/pkg/auth" "github.com/lukaszraczylo/gohoarder/pkg/cache" @@ -554,10 +555,10 @@ func (a *App) setupServer() error { frontendDir := "frontend/dist" if _, err := os.Stat(frontendDir); err == nil { log.Info().Str("dir", frontendDir).Msg("Serving frontend static files") - a.app.Static("/", frontendDir) + a.app.Use("/", static.New(frontendDir)) } else { log.Warn().Msg("Frontend dist directory not found, frontend won't be served") - a.app.Get("/", func(c *fiber.Ctx) error { + a.app.Get("/", func(c fiber.Ctx) error { return c.Type("html").SendString(` GoHoarder @@ -607,7 +608,7 @@ func (a *App) Run() error { Str("addr", addr). Str("cert_file", a.config.Server.TLS.CertFile). Msg("Starting Fiber server with TLS") - if err := a.app.ListenTLS(addr, a.config.Server.TLS.CertFile, a.config.Server.TLS.KeyFile); err != nil { + if err := a.app.Listen(addr, fiber.ListenConfig{CertFile: a.config.Server.TLS.CertFile, CertKeyFile: a.config.Server.TLS.KeyFile}); err != nil { errChan <- err } return @@ -643,6 +644,7 @@ func (a *App) Run() error { // Graceful shutdown return a.Shutdown() } + // Shutdown gracefully shuts down the application func (a *App) Shutdown() error { log.Info().Msg("Starting graceful shutdown") diff --git a/pkg/app/handlers.go b/pkg/app/handlers.go index bda0d99..3918cbb 100644 --- a/pkg/app/handlers.go +++ b/pkg/app/handlers.go @@ -4,7 +4,7 @@ import ( "strings" "time" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/lukaszraczylo/gohoarder/internal/version" "github.com/lukaszraczylo/gohoarder/pkg/metadata" "github.com/lukaszraczylo/gohoarder/pkg/websocket" @@ -12,7 +12,7 @@ import ( ) // handlePackages handles /api/packages endpoint -func (a *App) handlePackages(c *fiber.Ctx) error { +func (a *App) handlePackages(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") c.Set("Access-Control-Allow-Methods", "GET, DELETE, OPTIONS") @@ -38,7 +38,7 @@ func (a *App) handlePackages(c *fiber.Ctx) error { } // handleListPackages returns list of cached packages -func (a *App) handleListPackages(c *fiber.Ctx) error { +func (a *App) handleListPackages(c fiber.Ctx) error { ctx := c.Context() // Get packages from metadata store @@ -201,7 +201,7 @@ func (a *App) handleListPackages(c *fiber.Ctx) error { } // handleDeletePackage deletes a cached package -func (a *App) handleDeletePackage(c *fiber.Ctx) error { +func (a *App) handleDeletePackage(c fiber.Ctx) error { ctx := c.Context() // Parse path: /api/packages/{registry}/{name}/{version} @@ -331,7 +331,7 @@ func (a *App) handleDeletePackage(c *fiber.Ctx) error { } // handleStats handles /api/stats endpoint -func (a *App) handleStats(c *fiber.Ctx) error { +func (a *App) handleStats(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") c.Set("Access-Control-Allow-Methods", "GET, OPTIONS") @@ -421,7 +421,7 @@ func (a *App) handleStats(c *fiber.Ctx) error { // handleTimeSeriesStats handles /api/stats/timeseries endpoint // Returns time-series download statistics for charts -func (a *App) handleTimeSeriesStats(c *fiber.Ctx) error { +func (a *App) handleTimeSeriesStats(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") c.Set("Access-Control-Allow-Methods", "GET, OPTIONS") @@ -463,7 +463,7 @@ func (a *App) handleTimeSeriesStats(c *fiber.Ctx) error { // handleConfig handles /api/config endpoint // Returns runtime configuration for the frontend -func (a *App) handleConfig(c *fiber.Ctx) error { +func (a *App) handleConfig(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") c.Set("Access-Control-Allow-Methods", "GET, OPTIONS") @@ -497,7 +497,7 @@ func (a *App) handleConfig(c *fiber.Ctx) error { } // handleInfo handles /api/info endpoint -func (a *App) handleInfo(c *fiber.Ctx) error { +func (a *App) handleInfo(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") c.Set("Access-Control-Allow-Methods", "GET, OPTIONS") diff --git a/pkg/app/handlers_admin.go b/pkg/app/handlers_admin.go index e40cdf5..73e1675 100644 --- a/pkg/app/handlers_admin.go +++ b/pkg/app/handlers_admin.go @@ -3,7 +3,7 @@ package app import ( "time" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/lukaszraczylo/gohoarder/pkg/auth" "github.com/lukaszraczylo/gohoarder/pkg/errors" "github.com/lukaszraczylo/gohoarder/pkg/metadata" @@ -14,7 +14,7 @@ import ( // requireAdmin middleware checks for admin authentication. It accepts the API // key via either the Authorization Bearer header or the X-API-Key header // (shared extractAPIKey), so admin clients are not limited to the bearer form. -func (a *App) requireAdmin(c *fiber.Ctx) error { +func (a *App) requireAdmin(c fiber.Ctx) error { // Get API key from Authorization or X-API-Key header apiKey, ok := extractAPIKey(c) if !ok { @@ -43,7 +43,7 @@ func (a *App) requireAdmin(c *fiber.Ctx) error { } // handleAdminBypasses handles /api/admin/bypasses endpoint -func (a *App) handleAdminBypasses(c *fiber.Ctx) error { +func (a *App) handleAdminBypasses(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") c.Set("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE, OPTIONS") @@ -74,7 +74,7 @@ func (a *App) handleAdminBypasses(c *fiber.Ctx) error { } // handleListBypasses lists all CVE bypasses -func (a *App) handleListBypasses(c *fiber.Ctx) error { +func (a *App) handleListBypasses(c fiber.Ctx) error { ctx := c.Context() // Parse query parameters @@ -112,11 +112,11 @@ type CreateBypassRequest struct { } // handleCreateBypass creates a new CVE bypass -func (a *App) handleCreateBypass(c *fiber.Ctx) error { +func (a *App) handleCreateBypass(c fiber.Ctx) error { ctx := c.Context() var req CreateBypassRequest - if err := c.BodyParser(&req); err != nil { + if err := c.Bind().Body(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid JSON in request body"}) } @@ -179,7 +179,7 @@ func (a *App) handleCreateBypass(c *fiber.Ctx) error { } // handleGetBypass gets a specific bypass by ID -func (a *App) handleGetBypass(c *fiber.Ctx) error { +func (a *App) handleGetBypass(c fiber.Ctx) error { ctx := c.Context() // Extract ID from parameter @@ -217,7 +217,7 @@ type UpdateBypassRequest struct { } // handleUpdateBypass updates a bypass (activate/deactivate or extend expiration) -func (a *App) handleUpdateBypass(c *fiber.Ctx) error { +func (a *App) handleUpdateBypass(c fiber.Ctx) error { ctx := c.Context() // Extract ID from parameter @@ -228,7 +228,7 @@ func (a *App) handleUpdateBypass(c *fiber.Ctx) error { } var req UpdateBypassRequest - if err := c.BodyParser(&req); err != nil { + if err := c.Bind().Body(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid JSON in request body"}) } @@ -284,7 +284,7 @@ func (a *App) handleUpdateBypass(c *fiber.Ctx) error { } // handleDeleteBypass deletes a bypass -func (a *App) handleDeleteBypass(c *fiber.Ctx) error { +func (a *App) handleDeleteBypass(c fiber.Ctx) error { ctx := c.Context() // Extract ID from parameter diff --git a/pkg/app/handlers_analytics.go b/pkg/app/handlers_analytics.go index dbfbf02..4eb1ee6 100644 --- a/pkg/app/handlers_analytics.go +++ b/pkg/app/handlers_analytics.go @@ -3,12 +3,12 @@ package app import ( "strconv" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/rs/zerolog/log" ) // handleAnalyticsTopPackages returns the most downloaded packages -func (a *App) handleAnalyticsTopPackages(c *fiber.Ctx) error { +func (a *App) handleAnalyticsTopPackages(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") @@ -29,7 +29,7 @@ func (a *App) handleAnalyticsTopPackages(c *fiber.Ctx) error { } // handleAnalyticsTrendingPackages returns trending packages -func (a *App) handleAnalyticsTrendingPackages(c *fiber.Ctx) error { +func (a *App) handleAnalyticsTrendingPackages(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") @@ -50,7 +50,7 @@ func (a *App) handleAnalyticsTrendingPackages(c *fiber.Ctx) error { } // handleAnalyticsTrends returns download trends over time -func (a *App) handleAnalyticsTrends(c *fiber.Ctx) error { +func (a *App) handleAnalyticsTrends(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") @@ -62,7 +62,7 @@ func (a *App) handleAnalyticsTrends(c *fiber.Ctx) error { } // handleAnalyticsTotalStats returns overall statistics -func (a *App) handleAnalyticsTotalStats(c *fiber.Ctx) error { +func (a *App) handleAnalyticsTotalStats(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") @@ -72,7 +72,7 @@ func (a *App) handleAnalyticsTotalStats(c *fiber.Ctx) error { } // handleAnalyticsRegistryStats returns per-registry statistics -func (a *App) handleAnalyticsRegistryStats(c *fiber.Ctx) error { +func (a *App) handleAnalyticsRegistryStats(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") @@ -89,7 +89,7 @@ func (a *App) handleAnalyticsRegistryStats(c *fiber.Ctx) error { } // handleAnalyticsPackageStats returns statistics for a specific package -func (a *App) handleAnalyticsPackageStats(c *fiber.Ctx) error { +func (a *App) handleAnalyticsPackageStats(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") @@ -115,7 +115,7 @@ func (a *App) handleAnalyticsPackageStats(c *fiber.Ctx) error { } // handleAnalyticsSearch searches for packages matching a query -func (a *App) handleAnalyticsSearch(c *fiber.Ctx) error { +func (a *App) handleAnalyticsSearch(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") diff --git a/pkg/app/handlers_analytics_test.go b/pkg/app/handlers_analytics_test.go index ebf63b0..58c27c9 100644 --- a/pkg/app/handlers_analytics_test.go +++ b/pkg/app/handlers_analytics_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/lukaszraczylo/gohoarder/pkg/analytics" "github.com/stretchr/testify/suite" ) diff --git a/pkg/app/handlers_auth.go b/pkg/app/handlers_auth.go index 38eb61f..046aea2 100644 --- a/pkg/app/handlers_auth.go +++ b/pkg/app/handlers_auth.go @@ -3,7 +3,7 @@ package app import ( "time" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/lukaszraczylo/gohoarder/pkg/auth" "github.com/rs/zerolog/log" ) @@ -16,11 +16,11 @@ type GenerateAPIKeyRequest struct { } // handleGenerateAPIKey generates a new API key -func (a *App) handleGenerateAPIKey(c *fiber.Ctx) error { +func (a *App) handleGenerateAPIKey(c fiber.Ctx) error { c.Set("Content-Type", "application/json") var req GenerateAPIKeyRequest - if err := c.BodyParser(&req); err != nil { + if err := c.Bind().Body(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ "error": "invalid JSON in request body", }) @@ -82,7 +82,7 @@ func (a *App) handleGenerateAPIKey(c *fiber.Ctx) error { } // handleListAPIKeys lists all API keys -func (a *App) handleListAPIKeys(c *fiber.Ctx) error { +func (a *App) handleListAPIKeys(c fiber.Ctx) error { c.Set("Content-Type", "application/json") keys := a.authManager.ListAPIKeys() @@ -108,7 +108,7 @@ func (a *App) handleListAPIKeys(c *fiber.Ctx) error { } // handleRevokeAPIKey revokes an API key -func (a *App) handleRevokeAPIKey(c *fiber.Ctx) error { +func (a *App) handleRevokeAPIKey(c fiber.Ctx) error { c.Set("Content-Type", "application/json") keyID := c.Params("key_id") diff --git a/pkg/app/handlers_auth_test.go b/pkg/app/handlers_auth_test.go index 28ce01c..24c8dd6 100644 --- a/pkg/app/handlers_auth_test.go +++ b/pkg/app/handlers_auth_test.go @@ -5,8 +5,9 @@ import ( "encoding/json" "net/http/httptest" "testing" + "time" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/lukaszraczylo/gohoarder/pkg/auth" "github.com/stretchr/testify/suite" ) @@ -114,7 +115,7 @@ func (s *AuthHandlersTestSuite) TestHandleGenerateAPIKey() { req := httptest.NewRequest("POST", "/api/admin/keys", bytes.NewReader(bodyBytes)) req.Header.Set("Content-Type", "application/json") - resp, err := s.app.Test(req, 5000) // 5 second timeout for CI environments + resp, err := s.app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) // 5 second timeout for CI environments s.Require().NoError(err) s.Equal(tt.expectedStatus, resp.StatusCode) @@ -144,7 +145,7 @@ func (s *AuthHandlersTestSuite) TestHandleListAPIKeys() { _, _, _ = s.authManager.GenerateAPIKey("test-key-3", auth.RoleAdmin, nil) req := httptest.NewRequest("GET", "/api/admin/keys", nil) - resp, err := s.app.Test(req, 5000) // 5 second timeout for CI environments + resp, err := s.app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) // 5 second timeout for CI environments s.Require().NoError(err) s.Equal(200, resp.StatusCode) @@ -189,7 +190,7 @@ func (s *AuthHandlersTestSuite) TestHandleRevokeAPIKey() { for _, tt := range tests { s.Run(tt.name, func() { req := httptest.NewRequest("DELETE", "/api/admin/keys/"+tt.keyID, nil) - resp, err := s.app.Test(req, 5000) // 5 second timeout for CI environments + resp, err := s.app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) // 5 second timeout for CI environments s.Require().NoError(err) s.Equal(tt.expectedStatus, resp.StatusCode) @@ -207,7 +208,7 @@ func (s *AuthHandlersTestSuite) TestHandleGenerateAPIKeyInvalidJSON() { req := httptest.NewRequest("POST", "/api/admin/keys", bytes.NewReader([]byte("invalid json"))) req.Header.Set("Content-Type", "application/json") - resp, err := s.app.Test(req, 5000) // 5 second timeout for CI environments + resp, err := s.app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) // 5 second timeout for CI environments s.Require().NoError(err) s.Equal(400, resp.StatusCode) } @@ -221,7 +222,7 @@ func (s *AuthHandlersTestSuite) TestGenerateAndRevokeKeyFlow() { req1 := httptest.NewRequest("POST", "/api/admin/keys", bytes.NewReader(bodyBytes)) req1.Header.Set("Content-Type", "application/json") - resp1, err := s.app.Test(req1, 5000) // 5 second timeout for CI environments + resp1, err := s.app.Test(req1, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) // 5 second timeout for CI environments s.Require().NoError(err) s.Equal(201, resp1.StatusCode) @@ -235,7 +236,7 @@ func (s *AuthHandlersTestSuite) TestGenerateAndRevokeKeyFlow() { // List keys - should include our new key req2 := httptest.NewRequest("GET", "/api/admin/keys", nil) - resp2, err := s.app.Test(req2, 5000) // 5 second timeout for CI environments + resp2, err := s.app.Test(req2, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) // 5 second timeout for CI environments s.Require().NoError(err) s.Equal(200, resp2.StatusCode) @@ -257,13 +258,13 @@ func (s *AuthHandlersTestSuite) TestGenerateAndRevokeKeyFlow() { // Revoke the key req3 := httptest.NewRequest("DELETE", "/api/admin/keys/"+keyID, nil) - resp3, err := s.app.Test(req3, 5000) // 5 second timeout for CI environments + resp3, err := s.app.Test(req3, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) // 5 second timeout for CI environments s.Require().NoError(err) s.Equal(200, resp3.StatusCode) // List keys again - should not include the revoked key req4 := httptest.NewRequest("GET", "/api/admin/keys", nil) - resp4, err := s.app.Test(req4, 5000) // 5 second timeout for CI environments + resp4, err := s.app.Test(req4, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) // 5 second timeout for CI environments s.Require().NoError(err) s.Equal(200, resp4.StatusCode) diff --git a/pkg/app/handlers_prewarming.go b/pkg/app/handlers_prewarming.go index c51638f..804ab66 100644 --- a/pkg/app/handlers_prewarming.go +++ b/pkg/app/handlers_prewarming.go @@ -1,12 +1,12 @@ package app import ( - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/rs/zerolog/log" ) // handlePrewarmingStatus returns the status of the pre-warming worker -func (a *App) handlePrewarmingStatus(c *fiber.Ctx) error { +func (a *App) handlePrewarmingStatus(c fiber.Ctx) error { c.Set("Content-Type", "application/json") status := a.prewarmWorker.GetStatus() @@ -15,7 +15,7 @@ func (a *App) handlePrewarmingStatus(c *fiber.Ctx) error { } // handlePrewarmingTrigger manually triggers a pre-warming cycle -func (a *App) handlePrewarmingTrigger(c *fiber.Ctx) error { +func (a *App) handlePrewarmingTrigger(c fiber.Ctx) error { c.Set("Content-Type", "application/json") ctx := c.Context() @@ -36,11 +36,11 @@ type PrewarmPackageRequest struct { } // handlePrewarmingPackage pre-warms a specific package -func (a *App) handlePrewarmingPackage(c *fiber.Ctx) error { +func (a *App) handlePrewarmingPackage(c fiber.Ctx) error { c.Set("Content-Type", "application/json") var req PrewarmPackageRequest - if err := c.BodyParser(&req); err != nil { + if err := c.Bind().Body(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ "error": "invalid JSON in request body", }) diff --git a/pkg/app/handlers_prewarming_test.go b/pkg/app/handlers_prewarming_test.go index 941b2bc..57a7e1e 100644 --- a/pkg/app/handlers_prewarming_test.go +++ b/pkg/app/handlers_prewarming_test.go @@ -6,7 +6,7 @@ import ( "net/http/httptest" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/lukaszraczylo/gohoarder/pkg/prewarming" "github.com/stretchr/testify/suite" ) diff --git a/pkg/app/handlers_vulnerabilities.go b/pkg/app/handlers_vulnerabilities.go index f1c766e..107d905 100644 --- a/pkg/app/handlers_vulnerabilities.go +++ b/pkg/app/handlers_vulnerabilities.go @@ -3,13 +3,13 @@ package app import ( "strings" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/lukaszraczylo/gohoarder/pkg/metadata" "github.com/rs/zerolog/log" ) // handleVulnerabilities handles /api/packages/{registry}/{name}/{version}/vulnerabilities endpoint -func (a *App) handleVulnerabilities(c *fiber.Ctx) error { +func (a *App) handleVulnerabilities(c fiber.Ctx) error { c.Set("Content-Type", "application/json") c.Set("Access-Control-Allow-Origin", "*") c.Set("Access-Control-Allow-Methods", "GET, OPTIONS") diff --git a/pkg/app/middleware.go b/pkg/app/middleware.go index 79d11f8..de3ad8d 100644 --- a/pkg/app/middleware.go +++ b/pkg/app/middleware.go @@ -3,7 +3,7 @@ package app import ( "strings" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/lukaszraczylo/gohoarder/pkg/auth" "github.com/lukaszraczylo/gohoarder/pkg/errors" "github.com/rs/zerolog/log" @@ -20,7 +20,7 @@ const ( // extractAPIKey pulls the raw API key from either the Authorization bearer // header or the X-API-Key header. Returns ("", false) when neither is set or // the Authorization header has the wrong shape. -func extractAPIKey(c *fiber.Ctx) (string, bool) { +func extractAPIKey(c fiber.Ctx) (string, bool) { if h := strings.TrimSpace(c.Get("Authorization")); h != "" { // Expect: "Bearer ". Be tolerant of casing on the scheme. parts := strings.SplitN(h, " ", 2) @@ -40,7 +40,7 @@ func extractAPIKey(c *fiber.Ctx) (string, bool) { // writeAuthError sends a structured error response matching the project's // errors envelope (errors.Error JSON shape). Uses the HTTPStatusCode map so // callers don't need to remember which status maps to which code. -func writeAuthError(c *fiber.Ctx, code, message string) error { +func writeAuthError(c fiber.Ctx, code, message string) error { status, ok := errors.HTTPStatusCode[code] if !ok { status = fiber.StatusInternalServerError @@ -51,7 +51,7 @@ func writeAuthError(c *fiber.Ctx, code, message string) error { // requestIDFromCtx returns the request ID set by an upstream middleware or // the X-Request-ID header. Empty string when neither is available — callers // should treat empty as "no correlation id". -func requestIDFromCtx(c *fiber.Ctx) string { +func requestIDFromCtx(c fiber.Ctx) string { if v := c.Locals("request_id"); v != nil { if s, ok := v.(string); ok && s != "" { return s @@ -65,7 +65,7 @@ func requestIDFromCtx(c *fiber.Ctx) string { // resolved key plus a boolean indicating whether a key was present at all // (false when no header). The error is non-nil only when validation failed // (i.e. a key was present but invalid/expired). -func validateAndAttach(c *fiber.Ctx, authMgr *auth.Manager) (key *auth.APIKey, present bool, err error) { +func validateAndAttach(c fiber.Ctx, authMgr *auth.Manager) (key *auth.APIKey, present bool, err error) { rawKey, ok := extractAPIKey(c) if !ok { return nil, false, nil @@ -83,7 +83,7 @@ func validateAndAttach(c *fiber.Ctx, authMgr *auth.Manager) (key *auth.APIKey, p // API key. On success the resolved *auth.APIKey is stored in c.Locals under // LocalAuthKey. func RequireAuth(authMgr *auth.Manager) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { key, present, err := validateAndAttach(c, authMgr) if !present { log.Debug(). @@ -115,7 +115,7 @@ func RequireAuth(authMgr *auth.Manager) fiber.Handler { // requires the resolved key's role to be present in the supplied list (any-of // semantics). An empty roles list behaves like RequireAuth. func RequireRole(authMgr *auth.Manager, roles ...string) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { key, present, err := validateAndAttach(c, authMgr) if !present { return writeAuthError(c, errors.ErrCodeUnauthorized, "missing API key; provide Authorization: Bearer or X-API-Key header") @@ -146,7 +146,7 @@ func RequireRole(authMgr *auth.Manager, roles ...string) fiber.Handler { // then requires the resolved key to hold at least one of the supplied // permissions. An empty perms list behaves like RequireAuth. func RequirePermission(authMgr *auth.Manager, perms ...string) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { key, present, err := validateAndAttach(c, authMgr) if !present { return writeAuthError(c, errors.ErrCodeUnauthorized, "missing API key; provide Authorization: Bearer or X-API-Key header") @@ -177,7 +177,7 @@ func RequirePermission(authMgr *auth.Manager, perms ...string) fiber.Handler { // changes when the caller is authenticated (e.g. per-key rate limits) but // which still serve anonymous traffic. Locals are populated on success. func OptionalAuth(authMgr *auth.Manager) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { _, present, err := validateAndAttach(c, authMgr) if present && err != nil { // Key was provided but invalid — log for observability, continue diff --git a/pkg/app/middleware_test.go b/pkg/app/middleware_test.go index 2ebec38..1f03794 100644 --- a/pkg/app/middleware_test.go +++ b/pkg/app/middleware_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/lukaszraczylo/gohoarder/pkg/auth" "github.com/lukaszraczylo/gohoarder/pkg/errors" "github.com/stretchr/testify/require" @@ -23,9 +23,9 @@ func mwTestSetup(t *testing.T, role auth.Role, mw fiber.Handler) (*fiber.App, *a apiKey, raw, err := mgr.GenerateAPIKey("test-"+string(role), role, nil) require.NoError(t, err) - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", mw) - app.Get("/protected", func(c *fiber.Ctx) error { + app.Get("/protected", func(c fiber.Ctx) error { got, _ := c.Locals(LocalAuthKey).(*auth.APIKey) gotRole, _ := c.Locals(LocalAuthRole).(string) body := fiber.Map{"ok": true, "have_key": got != nil} @@ -48,7 +48,7 @@ func decodeErrorBody(t *testing.T, body io.Reader) errors.Error { func TestRequireAuth_NoHeader_Returns401(t *testing.T) { app, _, _, _ := mwTestSetup(t, auth.RoleReadOnly, RequireAuth(auth.New())) req := httptest.NewRequest("GET", "/protected", nil) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, fiber.StatusUnauthorized, resp.StatusCode) body := decodeErrorBody(t, resp.Body) @@ -63,7 +63,7 @@ func TestRequireAuth_BadKey_Returns401(t *testing.T) { app, _, _, _ := mwTestSetup(t, auth.RoleReadOnly, RequireAuth(mgr)) req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer not-a-real-key") - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, fiber.StatusUnauthorized, resp.StatusCode) body := decodeErrorBody(t, resp.Body) @@ -84,14 +84,14 @@ func TestRequireAuth_BadHeaderShape_Returns401(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { mgr := auth.New() - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", RequireAuth(mgr)) - app.Get("/protected", func(c *fiber.Ctx) error { return c.SendStatus(200) }) + app.Get("/protected", func(c fiber.Ctx) error { return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) if tc.value != "" { req.Header.Set(tc.header, tc.value) } - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, fiber.StatusUnauthorized, resp.StatusCode) }) @@ -103,9 +103,9 @@ func TestRequireAuth_ValidBearer_Returns200_AndPopulatesLocals(t *testing.T) { apiKey, raw, err := mgr.GenerateAPIKey("good", auth.RoleReadWrite, nil) require.NoError(t, err) - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", RequireAuth(mgr)) - app.Get("/protected", func(c *fiber.Ctx) error { + app.Get("/protected", func(c fiber.Ctx) error { k, _ := c.Locals(LocalAuthKey).(*auth.APIKey) require.NotNil(t, k) require.Equal(t, apiKey.ID, k.ID) @@ -115,7 +115,7 @@ func TestRequireAuth_ValidBearer_Returns200_AndPopulatesLocals(t *testing.T) { req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer "+raw) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) @@ -129,13 +129,13 @@ func TestRequireAuth_ValidXAPIKey_Returns200(t *testing.T) { _, raw, err := mgr.GenerateAPIKey("good", auth.RoleReadOnly, nil) require.NoError(t, err) - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", RequireAuth(mgr)) - app.Get("/protected", func(c *fiber.Ctx) error { return c.SendStatus(200) }) + app.Get("/protected", func(c fiber.Ctx) error { return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("X-API-Key", raw) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) } @@ -146,13 +146,13 @@ func TestRequireAuth_ExpiredKey_Returns401(t *testing.T) { _, raw, err := mgr.GenerateAPIKey("expired", auth.RoleReadOnly, &d) require.NoError(t, err) - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", RequireAuth(mgr)) - app.Get("/protected", func(c *fiber.Ctx) error { return c.SendStatus(200) }) + app.Get("/protected", func(c fiber.Ctx) error { return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer "+raw) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, fiber.StatusUnauthorized, resp.StatusCode) } @@ -162,13 +162,13 @@ func TestRequireRole_Match_Returns200(t *testing.T) { _, raw, err := mgr.GenerateAPIKey("admin", auth.RoleAdmin, nil) require.NoError(t, err) - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", RequireRole(mgr, string(auth.RoleAdmin), string(auth.RoleReadWrite))) - app.Get("/protected", func(c *fiber.Ctx) error { return c.SendStatus(200) }) + app.Get("/protected", func(c fiber.Ctx) error { return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer "+raw) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) } @@ -178,13 +178,13 @@ func TestRequireRole_Mismatch_Returns403(t *testing.T) { _, raw, err := mgr.GenerateAPIKey("ro", auth.RoleReadOnly, nil) require.NoError(t, err) - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", RequireRole(mgr, string(auth.RoleAdmin))) - app.Get("/protected", func(c *fiber.Ctx) error { return c.SendStatus(200) }) + app.Get("/protected", func(c fiber.Ctx) error { return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer "+raw) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, fiber.StatusForbidden, resp.StatusCode) body := decodeErrorBody(t, resp.Body) @@ -193,12 +193,12 @@ func TestRequireRole_Mismatch_Returns403(t *testing.T) { func TestRequireRole_NoHeader_Returns401(t *testing.T) { mgr := auth.New() - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", RequireRole(mgr, string(auth.RoleAdmin))) - app.Get("/protected", func(c *fiber.Ctx) error { return c.SendStatus(200) }) + app.Get("/protected", func(c fiber.Ctx) error { return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, fiber.StatusUnauthorized, resp.StatusCode) } @@ -208,13 +208,13 @@ func TestRequirePermission_Match_Returns200(t *testing.T) { _, raw, err := mgr.GenerateAPIKey("rw", auth.RoleReadWrite, nil) require.NoError(t, err) - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", RequirePermission(mgr, string(auth.PermissionWritePackage))) - app.Get("/protected", func(c *fiber.Ctx) error { return c.SendStatus(200) }) + app.Get("/protected", func(c fiber.Ctx) error { return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer "+raw) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) } @@ -224,43 +224,43 @@ func TestRequirePermission_Mismatch_Returns403(t *testing.T) { _, raw, err := mgr.GenerateAPIKey("ro", auth.RoleReadOnly, nil) require.NoError(t, err) - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", RequirePermission(mgr, string(auth.PermissionDeletePackage))) - app.Get("/protected", func(c *fiber.Ctx) error { return c.SendStatus(200) }) + app.Get("/protected", func(c fiber.Ctx) error { return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer "+raw) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, fiber.StatusForbidden, resp.StatusCode) } func TestOptionalAuth_NoHeader_Continues(t *testing.T) { mgr := auth.New() - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", OptionalAuth(mgr)) - app.Get("/protected", func(c *fiber.Ctx) error { + app.Get("/protected", func(c fiber.Ctx) error { require.Nil(t, c.Locals(LocalAuthKey)) return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) } func TestOptionalAuth_BadKey_ContinuesAnonymously(t *testing.T) { mgr := auth.New() - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", OptionalAuth(mgr)) - app.Get("/protected", func(c *fiber.Ctx) error { + app.Get("/protected", func(c fiber.Ctx) error { // Bad key should NOT populate locals. require.Nil(t, c.Locals(LocalAuthKey)) return c.SendStatus(200) }) req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer not-real") - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) } @@ -270,9 +270,9 @@ func TestOptionalAuth_GoodKey_PopulatesLocals(t *testing.T) { apiKey, raw, err := mgr.GenerateAPIKey("good", auth.RoleAdmin, nil) require.NoError(t, err) - app := fiber.New(fiber.Config{DisableStartupMessage: true}) + app := fiber.New(fiber.Config{}) app.Use("/protected", OptionalAuth(mgr)) - app.Get("/protected", func(c *fiber.Ctx) error { + app.Get("/protected", func(c fiber.Ctx) error { k, _ := c.Locals(LocalAuthKey).(*auth.APIKey) require.NotNil(t, k) require.Equal(t, apiKey.ID, k.ID) @@ -281,7 +281,7 @@ func TestOptionalAuth_GoodKey_PopulatesLocals(t *testing.T) { req := httptest.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer "+raw) - resp, err := app.Test(req, 5000) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 5 * time.Second, FailOnTimeout: true}) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) }