mirror of https://github.com/gofiber/fiber.git
♻️ refactor: merge some external middlewares to core (#2453)
* ♻️ refactor: merge adaptor, helmet, keyauth, redirect, rewrite middlewares to core
* fix linting issues
* fix linting issues
* fix linting issues
* update
pull/2456/head
parent
9cc10e942a
commit
c7c37d9b50
|
@ -627,7 +627,12 @@ Here is a list of middleware that are included within the Fiber framework.
|
|||
| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Adds a requestid to every request. |
|
||||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler if a predicate is true. |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
|
||||
## 🧬 External Middleware
|
||||
|
||||
|
@ -635,12 +640,7 @@ List of externally hosted middleware modules and maintained by the [Fiber team](
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -627,6 +627,11 @@ Aşağıda Fiber-in daxilində olan middleware-lər siyahı şəklində göstər
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session üçün middleware. Qeyd: Bu middleware Fiber-in öz storage struktrunu istifadə edir. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware-i verilən şərt true olduğu halda handler-i görməyərək üstündən ötüb keçir. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Bir request üçün maksimum vaxt əlavə edir. Əgər arada fasilə yaranarsa, onda proses məhz ErrorHandler-ə göndərilərək icra edilir. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key giriş middleware-i, key əsaslı bir authentication metodudur. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Yönləndirmə üçün middleware. |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware-i verilən qanunlara əsasən URL yolunu (path) yenidən yazır. Geri dönüşün icrası üçün uyğunluq təşkil edən təsviri linklərin yaradılması üçün nəzərdə tutulmuşdur. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Fiber request handler-dən net/http handler-ə çevirici. @arsmn-ə xüsusi təşəkkürlər! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Fərqli HTTP header istifadə edərək tətbiqi daha təhlükəsiz saxlamağa kömək edir. |
|
||||
|
||||
## 🧬 Xarici Middleware
|
||||
|
||||
|
@ -634,12 +639,7 @@ Aşağıda Fiber-in daxilində olan middleware-lər siyahı şəklində göstər
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Fiber request handler-dən net/http handler-ə çevirici. @arsmn-ə xüsusi təşəkkürlər! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Fərqli HTTP header istifadə edərək tətbiqi daha təhlükəsiz saxlamağa kömək edir. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT, JSON Web Token(JWT) girişi qaytaran bir middleware-dir. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key giriş middleware-i, key əsaslı bir authentication metodudur. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Yönləndirmə üçün middleware. |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware-i verilən qanunlara əsasən URL yolunu (path) yenidən yazır. Geri dönüşün icrası üçün uyğunluq təşkil edən təsviri linklərin yaradılması üçün nəzərdə tutulmuşdur. |
|
||||
| [storage](https://github.com/gofiber/storage) | Fiber-in Storage arxitekturasını dəstəkləyən bir sıra storage driver verir. Bu sayədə storage-ə ehtiyac duyan Fiber middleware-də rahatlıqla istifadə oluna bilər. |
|
||||
| [template](https://github.com/gofiber/template) | Bu paket, Fiber `v1.10.x`, Go versiyası 1.13 və ya daha yuxarı olduqda istifadə oluna bilər. 8 template mühərriki var. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Yerlilərin dəstəyi ilə WebSocket-ə əsaslanan Fiber üçün Fasthttp. |
|
||||
|
|
|
@ -627,6 +627,11 @@ func main() {
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 کاڵا دەرەکییەکان
|
||||
|
||||
|
@ -634,12 +639,7 @@ func main() {
|
|||
|
||||
| کاڵا | دەربارە |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -597,6 +597,11 @@ Hier finden Sie eine Liste der Middleware, die im Fiber-Framework enthalten ist.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 External Middleware
|
||||
|
||||
|
@ -604,12 +609,7 @@ Liste der extern gehosteten Middleware-Module, die vom [Fiber team](https://gith
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. || [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -597,6 +597,11 @@ Aquí está una lista del middleware incluido en el marco web Fiber.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 Middleware Externo
|
||||
|
||||
|
@ -604,12 +609,7 @@ Lista de módulos de middleware alojados externamente, y mantenidos por el [equi
|
|||
|
||||
| Middleware | Descripción |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -712,6 +712,11 @@ func main() {
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) |برای ذخیره و مدیریت شناسه کاربری یا session بازدید کنندگان استفاده .میشود|
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) |این میدلور میتواند با استفاده از شرط های تعیین شده درخواست هایی را نادیده بگیرد.|
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) |این میدلور محدودیت زمانی ای را برای درخواست ها تنظیم میکند، در صورتی که محدودیت به پایان برسد ErrorHandler صدا زده میشود.|
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
</div>
|
||||
</br></br>
|
||||
|
@ -728,12 +733,7 @@ func main() {
|
|||
|
||||
| Middleware | توضیحات |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -599,6 +599,11 @@ Here is a list of middleware that are included within the Fiber framework.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 External Middleware
|
||||
|
||||
|
@ -606,12 +611,7 @@ List of externally hosted middleware modules and maintained by the [Fiber team](
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -715,6 +715,11 @@ Here is a list of middleware that are included within the Fiber framework.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -734,12 +739,7 @@ Here is a list of middleware that are included within the Fiber framework.
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -600,6 +600,11 @@ Kumpulan `middleware` yang ada didalam kerangka kerja Fiber.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 Middleware External
|
||||
|
||||
|
@ -607,12 +612,7 @@ Kumpulan `middleware` yang dihost external dan diurus oleh [Tim Fiber](https://g
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -623,6 +623,11 @@ Qui una lista dei middleware inclusi con Fiber.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Middleware per sessioni. NOTA: Questo middleware usa il nostro Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Middleware che salta un wrapped handler se un predicate è vero. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Aggiunge un tempo massimo per una richiesta e lo manda a ErrorHandler se si supera. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Usa auth basato su chiavi. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Middleware per reinderizzare |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Riscrive la path all URL con le regole date. Può essere di aiuto per compatibilità o per creare link puliti e più descrittivi. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converte gli handler net/http a/da i request handlers di Fiber, grazie tante a @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Aiuta a mettere sicurezza alla tua app usando vari header HTTP. |
|
||||
|
||||
## 🧬 Middleware Esterni
|
||||
|
||||
|
@ -630,12 +635,7 @@ La lista dei moduli middleware hostati esternamente e mantenuti dal [team di Fib
|
|||
|
||||
| Middleware | Descrizione |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converte gli handler net/http a/da i request handlers di Fiber, grazie tante a @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Aiuta a mettere sicurezza alla tua app usando vari header HTTP. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | Usa JSON Web Token \(JWT\) auth. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Usa auth basato su chiavi. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Middleware per reinderizzare |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Riscrive la path all URL con le regole date. Può essere di aiuto per compatibilità o per creare link puliti e più descrittivi. |
|
||||
| [storage](https://github.com/gofiber/storage) | Dirver di storage che implementa la interfaccia Storage, fatto per essere usato con vari Fiber middleware. |
|
||||
| [template](https://github.com/gofiber/template) | Questo pachetto contiene 8 motori template che possono essere usati con Fiber `v1.10.x`. Versione di go neccesaria: 1.13+. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Basato su Fasthttp WebSocket per Fiber con supporto per Locals! |
|
||||
|
|
|
@ -602,6 +602,11 @@ func main() {
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 外部ミドルウェア
|
||||
|
||||
|
@ -609,12 +614,7 @@ func main() {
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -603,6 +603,11 @@ Fiber 프레임워크에 포함되는 미들웨어 목록입니다.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 External Middleware
|
||||
|
||||
|
@ -610,12 +615,7 @@ Fiber 프레임워크에 포함되는 미들웨어 목록입니다.
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -603,6 +603,11 @@ Here is a list of middleware that are included within the Fiber framework.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
|
||||
## 🧬 External Middleware
|
||||
|
||||
|
@ -610,12 +615,7 @@ List of externally hosted middleware modules and maintained by the [Fiber team](
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -597,6 +597,11 @@ Here is a list of middleware that are included within the Fiber framework.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 External Middleware
|
||||
|
||||
|
@ -604,12 +609,7 @@ List of externally hosted middleware modules and maintained by the [Fiber team](
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -604,6 +604,11 @@ func main() {
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 Внешние Middleware
|
||||
|
||||
|
@ -611,12 +616,7 @@ func main() {
|
|||
|
||||
| Middleware | Описание |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -668,6 +668,11 @@ Here is a list of middleware that are included within the Fiber framework.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
|
||||
## 🧬 External Middleware
|
||||
|
||||
|
@ -675,12 +680,7 @@ List of externally hosted middleware modules and maintained by the [Fiber team](
|
|||
|
||||
| Middleware | Description |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Redirect middleware |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. |
|
||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||
| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
|
||||
|
|
|
@ -597,6 +597,11 @@ Fiber'a dahil edilen middlewareların bir listesi aşağıda verilmiştir.
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session için middleware. NOTE: Bu middleware Fiber'in Storage yapısını kullanır. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware'ı verilen koşul `true` olduğunda handler'ı atlar ve işlemez. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Bir request için maksimum süre ekler ve aşılırsa ErrorHandler'a iletir. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware, key tabanlı bir authentication sağlar. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Yönlendirme middleware 'ı. |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware, sağlanan kurallara göre URL yolunu yeniden yazar. Geriye dönük uyumluluk için veya yalnızca daha temiz ve daha açıklayıcı bağlantılar oluşturmak için yardımcı olabilir. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Fiber request handlerdan net/http handlerları için dönüştürücü, @arsmn'a özel teşekkürler! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Çeşitli HTTP headerları ayarlayarak uygulamalarınızın güvenliğini sağlamaya yardımcı olur. |
|
||||
|
||||
## 🧬 Harici Middlewarelar
|
||||
|
||||
|
@ -604,12 +609,7 @@ Harici olarak barındırılan middlewareların modüllerinin listesi. Bu middlew
|
|||
|
||||
| Middleware | Açıklama |
|
||||
| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Fiber request handlerdan net/http handlerları için dönüştürücü, @arsmn'a özel teşekkürler! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Çeşitli HTTP headerları ayarlayarak uygulamalarınızın güvenliğini sağlamaya yardımcı olur. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT, bir JSON Web Token \(JWT\) yetkilendirmesi döndüren middleware. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware, key tabanlı bir authentication sağlar. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Yönlendirme middleware 'ı. |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware, sağlanan kurallara göre URL yolunu yeniden yazar. Geriye dönük uyumluluk için veya yalnızca daha temiz ve daha açıklayıcı bağlantılar oluşturmak için yardımcı olabilir. |
|
||||
| [storage](https://github.com/gofiber/storage) | Fiber'in Storage yapısını destekleyen birçok storage driver'ı verir. Bu sayede depolama gerektiren Fiber middlewarelarında kolaylıkla kullanılabilir. |
|
||||
| [template](https://github.com/gofiber/template) | Bu paket, Fiber `v2.x.x`, Go sürüm 1.17 veya üzeri gerekli olduğunda kullanılabilecek 9 template motoru içerir. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | Yereller desteğiyle Fiber için Fasthttp WebSocket'a dayalıdır! |
|
||||
|
|
|
@ -632,6 +632,11 @@ func main() {
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Middleware для сеансів. ПРИМІТКА: Цей middleware використовує наш пакет зберігання. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Middleware який пропускає упакований обробник, якщо предикат є істинним. |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Додає максимальний час для запиту та пересилає до ErrorHandler, якщо його перевищено. |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Middleware для автентифікації по ключам. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Middleware для перенаправлення. |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Middleware для перезапису URL-адреси на основі наданих правил. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Конвентор для обробників net/http до/з обробників запитів Fiber, особлива подяка @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Допомагає захистити ваші програми, встановлюючи різні заголовки HTTP. |
|
||||
|
||||
## 🧬 Зовнішні Middleware
|
||||
|
||||
|
@ -639,12 +644,7 @@ func main() {
|
|||
|
||||
| Middleware | Опис |
|
||||
| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | Конвентор для обробників net/http до/з обробників запитів Fiber, особлива подяка @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | Допомагає захистити ваші програми, встановлюючи різні заголовки HTTP. |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT повертає middleware автентифікації JSON Web Token \(JWT\). |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Middleware для автентифікації по ключам. |
|
||||
| [redirect](https://github.com/gofiber/redirect) | Middleware для перенаправлення. |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Middleware для перезапису URL-адреси на основі наданих правил. |
|
||||
| [storage](https://github.com/gofiber/storage) | Драйвер зберігання який може використовуватися в різних middleware. |
|
||||
| [template](https://github.com/gofiber/template) | Цей пакет містить 8 модулів шаблонів, які можна використовувати з Fiber `v1.10.x` Потрібно версія Go 1.13 або новішу. |
|
||||
| [websocket](https://github.com/gofiber/websocket) | На основі Fasthttp WebSocket для Fiber з підтримкою місцевих користувачів! |
|
||||
|
|
|
@ -605,6 +605,11 @@ func main() {
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session 中间件. 注意: 此中间件使用了我们的存储包. |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip 中间件会在判断条为 true 时忽略此次请求 |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | 添加请求的最大时间,如果超时则发送给ErrorHandler 进行处理. |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | net/http 处理程序与 Fiber 请求处理程序之间的转换器,特别感谢 @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | 通过设置各种 HTTP 头帮助保护您的应用程序 |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth 中间件提供基于密钥的身份验证 |
|
||||
| [redirect](https://github.com/gofiber/redirect) | 用于重定向请求的中间件 |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite 中间件根据提供的规则重写URL路径。它有助于向后兼容或者创建更清晰、更具描述性的链接 |
|
||||
|
||||
## 🧬 外部中间件
|
||||
|
||||
|
@ -612,12 +617,7 @@ func main() {
|
|||
|
||||
| 中间件 | 描述 |
|
||||
|:--------------------------------------------------|:-------------------------------------------------------------------------------------------|
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | net/http 处理程序与 Fiber 请求处理程序之间的转换器,特别感谢 @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | 通过设置各种 HTTP 头帮助保护您的应用程序 |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT 返回一个 JSON Web Token\(JWT\) 身份验证中间件 |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth 中间件提供基于密钥的身份验证 |
|
||||
| [redirect](https://github.com/gofiber/redirect) | 用于重定向请求的中间件 |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | Rewrite 中间件根据提供的规则重写URL路径。它有助于向后兼容或者创建更清晰、更具描述性的链接 |
|
||||
| [storage](https://github.com/gofiber/storage) | 包含实现 Storage 接口的数据库驱动,它的设计旨在配合 fiber 的其他中间件来进行使用 |
|
||||
| [template](https://github.com/gofiber/template) | 该中间件包含 8 个模板引擎,可与 Fiber `v1.10.x` Go 1.13或更高版本一起使用 |
|
||||
| [websocket](https://github.com/gofiber/websocket) | 基于 Fasthttp WebSocket for Fiber 实现,支持使用 [Locals](https://docs.gofiber.io/api/ctx#locals) ! |
|
||||
|
|
|
@ -636,6 +636,11 @@ func main() {
|
|||
| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | 連線階段中介模組。注意:這個中介模組有用到我們的 Storage 套件。 |
|
||||
| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | 略過中介模組,會在條件成立時略過封裝過的處理常式。 |
|
||||
| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | 為請求加上最長時限,並在逾時後轉送至錯誤處理常式 (ErrorHandler)。 |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth 中介模組提供以金鑰為基礎的認證模式。 |
|
||||
| [redirect](https://github.com/gofiber/redirect) | 用來重新導向的中介模組。 |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | 重寫 (Rewrite) 中介模組:根據提供規則重寫 URL 路徑,適合用來向後相容,或者是製作更乾淨且更好懂的連結。 |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | 將 net/http 處理常式轉換至 Fiber 處理常式,或者是反著做。特別感謝 @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | 透過設定多種 HTTP 標頭,協助保護您應用程式的安全。 |
|
||||
|
||||
## 🧬 外掛中介模組
|
||||
|
||||
|
@ -643,12 +648,7 @@ func main() {
|
|||
|
||||
| 中介模組 | 描述 |
|
||||
| :------------------------------------------------ | :----------------------------------------------------------------------------------------------------- |
|
||||
| [adaptor](https://github.com/gofiber/adaptor) | 將 net/http 處理常式轉換至 Fiber 處理常式,或者是反著做。特別感謝 @arsmn! |
|
||||
| [helmet](https://github.com/gofiber/helmet) | 透過設定多種 HTTP 標頭,協助保護您應用程式的安全。 |
|
||||
| [jwt](https://github.com/gofiber/jwt) | JWT 回傳 JSON Web Token \(JWT\) 認證中介模組。 |
|
||||
| [keyauth](https://github.com/gofiber/keyauth) | Key auth 中介模組提供以金鑰為基礎的認證模式。 |
|
||||
| [redirect](https://github.com/gofiber/redirect) | 用來重新導向的中介模組。 |
|
||||
| [rewrite](https://github.com/gofiber/rewrite) | 重寫 (Rewrite) 中介模組:根據提供規則重寫 URL 路徑,適合用來向後相容,或者是製作更乾淨且更好懂的連結。 |
|
||||
| [storage](https://github.com/gofiber/storage) | 已經做好,實作 Storage 介面的儲存區驅動模組,設計用來與各種 Fiber 中介模組搭配使用。 |
|
||||
| [template](https://github.com/gofiber/template) | 本套件包含 8 種樣板引擎,可以和 Fiber `v1.10.x` 一起使用。需要 Go 1.13 或更新版本。 |
|
||||
| [websocket](https://github.com/gofiber/websocket) | 適用於 Fiber,建基於 Fasthttp 的 WebSocket。支援本機空間 (Locals)! |
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
id: adaptor
|
||||
title: Adaptor
|
||||
---
|
||||
|
||||
Converter for net/http handlers to/from Fiber request handlers, special thanks to [@arsmn](https://github.com/arsmn)!
|
||||
|
||||
## Signatures
|
||||
| Name | Signature | Description
|
||||
| :--- | :--- | :---
|
||||
| HTTPHandler | `HTTPHandler(h http.Handler) fiber.Handler` | http.Handler -> fiber.Handler
|
||||
| HTTPHandlerFunc | `HTTPHandlerFunc(h http.HandlerFunc) fiber.Handler` | http.HandlerFunc -> fiber.Handler
|
||||
| HTTPMiddleware | `HTTPHandlerFunc(mw func(http.Handler) http.Handler) fiber.Handler` | func(http.Handler) http.Handler -> fiber.Handler
|
||||
| FiberHandler | `FiberHandler(h fiber.Handler) http.Handler` | fiber.Handler -> http.Handler
|
||||
| FiberHandlerFunc | `FiberHandlerFunc(h fiber.Handler) http.HandlerFunc` | fiber.Handler -> http.HandlerFunc
|
||||
| FiberApp | `FiberApp(app *fiber.App) http.HandlerFunc` | Fiber app -> http.HandlerFunc
|
||||
| CopyContextToFiberContex | `CopyContextToFiberContext(context interface{}, requestContext *fasthttp.RequestCtx)` | context.Context -> fasthttp.RequestCtx
|
||||
|
||||
## Examples
|
||||
|
||||
### net/http to Fiber
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/v2/middleware/adaptor"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// New fiber app
|
||||
app := fiber.New()
|
||||
|
||||
// http.Handler -> fiber.Handler
|
||||
app.Get("/", adaptor.HTTPHandler(handler(greet)))
|
||||
|
||||
// http.HandlerFunc -> fiber.Handler
|
||||
app.Get("/func", adaptor.HTTPHandlerFunc(greet))
|
||||
|
||||
// Listen on port 3000
|
||||
app.Listen(":3000")
|
||||
}
|
||||
|
||||
func handler(f http.HandlerFunc) http.Handler {
|
||||
return http.HandlerFunc(f)
|
||||
}
|
||||
|
||||
func greet(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprint(w, "Hello World!")
|
||||
}
|
||||
```
|
||||
|
||||
### net/http middleware to Fiber
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/v2/middleware/adaptor"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// New fiber app
|
||||
app := fiber.New()
|
||||
|
||||
// http middleware -> fiber.Handler
|
||||
app.Use(adaptor.HTTPMiddleware(logMiddleware))
|
||||
|
||||
// Listen on port 3000
|
||||
app.Listen(":3000")
|
||||
}
|
||||
|
||||
func logMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println("log middleware")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Fiber Handler to net/http
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/v2/middleware/adaptor"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// fiber.Handler -> http.Handler
|
||||
http.Handle("/", adaptor.FiberHandler(greet))
|
||||
|
||||
// fiber.Handler -> http.HandlerFunc
|
||||
http.HandleFunc("/func", adaptor.FiberHandlerFunc(greet))
|
||||
|
||||
// Listen on port 3000
|
||||
http.ListenAndServe(":3000", nil)
|
||||
}
|
||||
|
||||
func greet(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello World!")
|
||||
}
|
||||
```
|
||||
|
||||
### Fiber App to net/http
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/v2/middleware/adaptor"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"net/http"
|
||||
)
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/greet", greet)
|
||||
|
||||
// Listen on port 3000
|
||||
http.ListenAndServe(":3000", adaptor.FiberApp(app))
|
||||
}
|
||||
|
||||
func greet(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello World!")
|
||||
}
|
||||
```
|
|
@ -11,13 +11,6 @@ Filesystem middleware for [Fiber](https://github.com/gofiber/fiber) that enables
|
|||
**To handle paths with spaces (or other url encoded values) make sure to set `fiber.Config{ UnescapePath: true }`**
|
||||
:::
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [Signatures](filesystem.md#signatures)
|
||||
* [Examples](filesystem.md#examples)
|
||||
* [Config](filesystem.md#config)
|
||||
* [Default Config](filesystem.md#default-config)
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
---
|
||||
id: helmet
|
||||
title: Helmet
|
||||
---
|
||||
|
||||
Helmet middleware helps secure your apps by setting various HTTP headers.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/helmet"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(helmet.New())
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Welcome!")
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
**Test:**
|
||||
|
||||
```curl
|
||||
curl -I http://localhost:3000
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
```go
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Next defines a function to skip middleware.
|
||||
// Optional. Default: nil
|
||||
Next func(*fiber.Ctx) bool
|
||||
|
||||
// XSSProtection
|
||||
// Optional. Default value "0".
|
||||
XSSProtection string
|
||||
|
||||
// ContentTypeNosniff
|
||||
// Optional. Default value "nosniff".
|
||||
ContentTypeNosniff string
|
||||
|
||||
// XFrameOptions
|
||||
// Optional. Default value "SAMEORIGIN".
|
||||
// Possible values: "SAMEORIGIN", "DENY", "ALLOW-FROM uri"
|
||||
XFrameOptions string
|
||||
|
||||
// HSTSMaxAge
|
||||
// Optional. Default value 0.
|
||||
HSTSMaxAge int
|
||||
|
||||
// HSTSExcludeSubdomains
|
||||
// Optional. Default value false.
|
||||
HSTSExcludeSubdomains bool
|
||||
|
||||
// ContentSecurityPolicy
|
||||
// Optional. Default value "".
|
||||
ContentSecurityPolicy string
|
||||
|
||||
// CSPReportOnly
|
||||
// Optional. Default value false.
|
||||
CSPReportOnly bool
|
||||
|
||||
// HSTSPreloadEnabled
|
||||
// Optional. Default value false.
|
||||
HSTSPreloadEnabled bool
|
||||
|
||||
// ReferrerPolicy
|
||||
// Optional. Default value "ReferrerPolicy".
|
||||
ReferrerPolicy string
|
||||
|
||||
// Permissions-Policy
|
||||
// Optional. Default value "".
|
||||
PermissionPolicy string
|
||||
|
||||
// Cross-Origin-Embedder-Policy
|
||||
// Optional. Default value "require-corp".
|
||||
CrossOriginEmbedderPolicy string
|
||||
|
||||
// Cross-Origin-Opener-Policy
|
||||
// Optional. Default value "same-origin".
|
||||
CrossOriginOpenerPolicy string
|
||||
|
||||
// Cross-Origin-Resource-Policy
|
||||
// Optional. Default value "same-origin".
|
||||
CrossOriginResourcePolicy string
|
||||
|
||||
// Origin-Agent-Cluster
|
||||
// Optional. Default value "?1".
|
||||
OriginAgentCluster string
|
||||
|
||||
// X-DNS-Prefetch-Control
|
||||
// Optional. Default value "off".
|
||||
XDNSPrefetchControl string
|
||||
|
||||
// X-Download-Options
|
||||
// Optional. Default value "noopen".
|
||||
XDownloadOptions string
|
||||
|
||||
// X-Permitted-Cross-Domain-Policies
|
||||
// Optional. Default value "none".
|
||||
XPermittedCrossDomain string
|
||||
}
|
||||
```
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
XSSProtection: "0",
|
||||
ContentTypeNosniff: "nosniff",
|
||||
XFrameOptions: "SAMEORIGIN",
|
||||
ReferrerPolicy: "no-referrer",
|
||||
CrossOriginEmbedderPolicy: "require-corp",
|
||||
CrossOriginOpenerPolicy: "same-origin",
|
||||
CrossOriginResourcePolicy: "same-origin",
|
||||
OriginAgentCluster: "?1",
|
||||
XDNSPrefetchControl: "off",
|
||||
XDownloadOptions: "noopen",
|
||||
XPermittedCrossDomain: "none",
|
||||
}
|
||||
```
|
|
@ -0,0 +1,272 @@
|
|||
---
|
||||
id: keyauth
|
||||
title: Keyauth
|
||||
---
|
||||
|
||||
Key auth middleware provides a key based authentication.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/keyauth"
|
||||
)
|
||||
|
||||
var (
|
||||
apiKey = "correct horse battery staple"
|
||||
)
|
||||
|
||||
func validateAPIKey(c *fiber.Ctx, key string) (bool, error) {
|
||||
hashedAPIKey := sha256.Sum256([]byte(apiKey))
|
||||
hashedKey := sha256.Sum256([]byte(key))
|
||||
|
||||
if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 {
|
||||
return true, nil
|
||||
}
|
||||
return false, keyauth.ErrMissingOrMalformedAPIKey
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
// note that the keyauth middleware needs to be defined before the routes are defined!
|
||||
app.Use(keyauth.New(keyauth.Config{
|
||||
KeyLookup: "cookie:access_token",
|
||||
Validator: validateAPIKey,
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated!")
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
**Test:**
|
||||
|
||||
```bash
|
||||
# No api-key specified -> 400 missing
|
||||
curl http://localhost:3000
|
||||
#> missing or malformed API Key
|
||||
|
||||
curl --cookie "access_token=correct horse battery staple" http://localhost:3000
|
||||
#> Successfully authenticated!
|
||||
|
||||
curl --cookie "access_token=Clearly A Wrong Key" http://localhost:3000
|
||||
#> missing or malformed API Key
|
||||
```
|
||||
|
||||
For a more detailed example, see also the [`github.com/gofiber/recipes`](https://github.com/gofiber/recipes) repository and specifically the `fiber-envoy-extauthz` repository and the [`keyauth example`](https://github.com/gofiber/recipes/blob/master/fiber-envoy-extauthz/authz/main.go) code.
|
||||
|
||||
|
||||
### Authenticate only certain endpoints
|
||||
|
||||
If you want to authenticate only certain endpoints, you can use the `Config` of keyauth and apply a filter function (eg. `authFilter`) like so
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/keyauth"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
apiKey = "correct horse battery staple"
|
||||
protectedURLs = []*regexp.Regexp{
|
||||
regexp.MustCompile("^/authenticated$"),
|
||||
regexp.MustCompile("^/auth2$"),
|
||||
}
|
||||
)
|
||||
|
||||
func validateAPIKey(c *fiber.Ctx, key string) (bool, error) {
|
||||
hashedAPIKey := sha256.Sum256([]byte(apiKey))
|
||||
hashedKey := sha256.Sum256([]byte(key))
|
||||
|
||||
if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 {
|
||||
return true, nil
|
||||
}
|
||||
return false, keyauth.ErrMissingOrMalformedAPIKey
|
||||
}
|
||||
|
||||
func authFilter(c *fiber.Ctx) bool {
|
||||
originalURL := strings.ToLower(c.OriginalURL())
|
||||
|
||||
for _, pattern := range protectedURLs {
|
||||
if pattern.MatchString(originalURL) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(keyauth.New(keyauth.Config{
|
||||
Next: authFilter,
|
||||
KeyLookup: "cookie:access_token",
|
||||
Validator: validateAPIKey,
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Welcome")
|
||||
})
|
||||
app.Get("/authenticated", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated!")
|
||||
})
|
||||
app.Get("/auth2", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated 2!")
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
Which results in this
|
||||
|
||||
```bash
|
||||
# / does not need to be authenticated
|
||||
curl http://localhost:3000
|
||||
#> Welcome
|
||||
|
||||
# /authenticated needs to be authenticated
|
||||
curl --cookie "access_token=correct horse battery staple" http://localhost:3000/authenticated
|
||||
#> Successfully authenticated!
|
||||
|
||||
# /auth2 needs to be authenticated too
|
||||
curl --cookie "access_token=correct horse battery staple" http://localhost:3000/auth2
|
||||
#> Successfully authenticated 2!
|
||||
```
|
||||
|
||||
### Specifying middleware in the handler
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/keyauth"
|
||||
)
|
||||
|
||||
const (
|
||||
apiKey = "my-super-secret-key"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
authMiddleware := keyauth.New(keyauth.Config{
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
hashedAPIKey := sha256.Sum256([]byte(apiKey))
|
||||
hashedKey := sha256.Sum256([]byte(key))
|
||||
|
||||
if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 {
|
||||
return true, nil
|
||||
}
|
||||
return false, keyauth.ErrMissingOrMalformedAPIKey
|
||||
},
|
||||
})
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Welcome")
|
||||
})
|
||||
|
||||
app.Get("/allowed", authMiddleware, func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated!")
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
Which results in this
|
||||
|
||||
```bash
|
||||
# / does not need to be authenticated
|
||||
curl http://localhost:3000
|
||||
#> Welcome
|
||||
|
||||
# /allowed needs to be authenticated too
|
||||
curl --header "Authorization: Bearer my-super-secret-key" http://localhost:3000/allowed
|
||||
#> Successfully authenticated!
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
```go
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Next defines a function to skip middleware.
|
||||
// Optional. Default: nil
|
||||
Next func(*fiber.Ctx) bool
|
||||
|
||||
// SuccessHandler defines a function which is executed for a valid key.
|
||||
// Optional. Default: nil
|
||||
SuccessHandler fiber.Handler
|
||||
|
||||
// ErrorHandler defines a function which is executed for an invalid key.
|
||||
// It may be used to define a custom error.
|
||||
// Optional. Default: 401 Invalid or expired key
|
||||
ErrorHandler fiber.ErrorHandler
|
||||
|
||||
// KeyLookup is a string in the form of "<source>:<name>" that is used
|
||||
// to extract key from the request.
|
||||
// Optional. Default value "header:Authorization".
|
||||
// Possible values:
|
||||
// - "header:<name>"
|
||||
// - "query:<name>"
|
||||
// - "form:<name>"
|
||||
// - "param:<name>"
|
||||
// - "cookie:<name>"
|
||||
KeyLookup string
|
||||
|
||||
// AuthScheme to be used in the Authorization header.
|
||||
// Optional. Default value "Bearer".
|
||||
AuthScheme string
|
||||
|
||||
// Validator is a function to validate key.
|
||||
Validator func(*fiber.Ctx, string) (bool, error)
|
||||
|
||||
// Context key to store the bearertoken from the token into context.
|
||||
// Optional. Default: "token".
|
||||
ContextKey string
|
||||
}
|
||||
```
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
SuccessHandler: func(c *fiber.Ctx) error {
|
||||
return c.Next()
|
||||
},
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
if err == ErrMissingOrMalformedAPIKey {
|
||||
return c.Status(fiber.StatusUnauthorized).SendString(err.Error())
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).SendString("Invalid or expired API Key")
|
||||
},
|
||||
KeyLookup: "header:" + fiber.HeaderAuthorization,
|
||||
AuthScheme: "Bearer",
|
||||
ContextKey: "token",
|
||||
}
|
||||
```
|
|
@ -5,9 +5,6 @@ title: Pprof
|
|||
|
||||
Pprof middleware for [Fiber](https://github.com/gofiber/fiber) that serves via its HTTP server runtime profiling data in the format expected by the pprof visualization tool. The package is typically only imported for the side effect of registering its HTTP handlers. The handled paths all begin with /debug/pprof/.
|
||||
|
||||
* [Signatures](pprof.md#signatures)
|
||||
* [Examples](pprof.md#examples)
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
id: redirect
|
||||
title: Redirect
|
||||
---
|
||||
|
||||
Redirection middleware for Fiber.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/redirect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(redirect.New(redirect.Config{
|
||||
Rules: map[string]string{
|
||||
"/old": "/new",
|
||||
"/old/*": "/new/$1",
|
||||
},
|
||||
StatusCode: 301,
|
||||
}))
|
||||
|
||||
app.Get("/new", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
app.Get("/new/*", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Wildcard: " + c.Params("*"))
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
**Test:**
|
||||
|
||||
```curl
|
||||
curl http://localhost:3000/old
|
||||
curl http://localhost:3000/old/hello
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
```go
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Filter defines a function to skip middleware.
|
||||
// Optional. Default: nil
|
||||
Next func(*fiber.Ctx) bool
|
||||
|
||||
// Rules defines the URL path rewrite rules. The values captured in asterisk can be
|
||||
// retrieved by index e.g. $1, $2 and so on.
|
||||
// Required. Example:
|
||||
// "/old": "/new",
|
||||
// "/api/*": "/$1",
|
||||
// "/js/*": "/public/javascripts/$1",
|
||||
// "/users/*/orders/*": "/user/$1/order/$2",
|
||||
Rules map[string]string
|
||||
|
||||
// The status code when redirecting
|
||||
// This is ignored if Redirect is disabled
|
||||
// Optional. Default: 302 (fiber.StatusFound)
|
||||
StatusCode int
|
||||
|
||||
rulesRegex map[*regexp.Regexp]string
|
||||
}
|
||||
```
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
StatusCode: fiber.StatusFound,
|
||||
}
|
||||
```
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
id: rewrite
|
||||
title: Rewrite
|
||||
---
|
||||
|
||||
Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links.
|
||||
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
### Examples
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/rewrite"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(rewrite.New(rewrite.Config{
|
||||
Rules: map[string]string{
|
||||
"/old": "/new",
|
||||
"/old/*": "/new/$1",
|
||||
},
|
||||
}))
|
||||
|
||||
app.Get("/new", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
app.Get("/new/*", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Wildcard: " + c.Params("*"))
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Test:**
|
||||
|
||||
```curl
|
||||
curl http://localhost:3000/old
|
||||
curl http://localhost:3000/old/hello
|
||||
```
|
|
@ -0,0 +1,163 @@
|
|||
package adaptor
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
"github.com/valyala/fasthttp"
|
||||
"github.com/valyala/fasthttp/fasthttpadaptor"
|
||||
)
|
||||
|
||||
// HTTPHandlerFunc wraps net/http handler func to fiber handler
|
||||
func HTTPHandlerFunc(h http.HandlerFunc) fiber.Handler {
|
||||
return HTTPHandler(h)
|
||||
}
|
||||
|
||||
// HTTPHandler wraps net/http handler to fiber handler
|
||||
func HTTPHandler(h http.Handler) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
handler := fasthttpadaptor.NewFastHTTPHandler(h)
|
||||
handler(c.Context())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// CopyContextToFiberContext copies the values of context.Context to a fasthttp.RequestCtx
|
||||
func CopyContextToFiberContext(context interface{}, requestContext *fasthttp.RequestCtx) {
|
||||
contextValues := reflect.ValueOf(context).Elem()
|
||||
contextKeys := reflect.TypeOf(context).Elem()
|
||||
if contextKeys.Kind() == reflect.Struct {
|
||||
var lastKey interface{}
|
||||
for i := 0; i < contextValues.NumField(); i++ {
|
||||
reflectValue := contextValues.Field(i)
|
||||
/* #nosec */
|
||||
reflectValue = reflect.NewAt(reflectValue.Type(), unsafe.Pointer(reflectValue.UnsafeAddr())).Elem()
|
||||
|
||||
reflectField := contextKeys.Field(i)
|
||||
|
||||
if reflectField.Name == "noCopy" {
|
||||
break
|
||||
} else if reflectField.Name == "Context" {
|
||||
CopyContextToFiberContext(reflectValue.Interface(), requestContext)
|
||||
} else if reflectField.Name == "key" {
|
||||
lastKey = reflectValue.Interface()
|
||||
} else if lastKey != nil && reflectField.Name == "val" {
|
||||
requestContext.SetUserValue(lastKey, reflectValue.Interface())
|
||||
} else {
|
||||
lastKey = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPMiddleware wraps net/http middleware to fiber middleware
|
||||
func HTTPMiddleware(mw func(http.Handler) http.Handler) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
var next bool
|
||||
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
next = true
|
||||
// Convert again in case request may modify by middleware
|
||||
c.Request().Header.SetMethod(r.Method)
|
||||
c.Request().SetRequestURI(r.RequestURI)
|
||||
c.Request().SetHost(r.Host)
|
||||
for key, val := range r.Header {
|
||||
for _, v := range val {
|
||||
c.Request().Header.Set(key, v)
|
||||
}
|
||||
}
|
||||
CopyContextToFiberContext(r.Context(), c.Context())
|
||||
})
|
||||
|
||||
if err := HTTPHandler(mw(nextHandler))(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if next {
|
||||
return c.Next()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// FiberHandler wraps fiber handler to net/http handler
|
||||
func FiberHandler(h fiber.Handler) http.Handler {
|
||||
return FiberHandlerFunc(h)
|
||||
}
|
||||
|
||||
// FiberHandlerFunc wraps fiber handler to net/http handler func
|
||||
func FiberHandlerFunc(h fiber.Handler) http.HandlerFunc {
|
||||
return handlerFunc(fiber.New(), h)
|
||||
}
|
||||
|
||||
// FiberApp wraps fiber app to net/http handler func
|
||||
func FiberApp(app *fiber.App) http.HandlerFunc {
|
||||
return handlerFunc(app)
|
||||
}
|
||||
|
||||
func handlerFunc(app *fiber.App, h ...fiber.Handler) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// New fasthttp request
|
||||
req := fasthttp.AcquireRequest()
|
||||
defer fasthttp.ReleaseRequest(req)
|
||||
// Convert net/http -> fasthttp request
|
||||
if r.Body != nil {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.SetContentLength(len(body))
|
||||
_, err = req.BodyWriter().Write(body)
|
||||
if err != nil {
|
||||
http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
req.Header.SetMethod(r.Method)
|
||||
req.SetRequestURI(r.RequestURI)
|
||||
req.SetHost(r.Host)
|
||||
for key, val := range r.Header {
|
||||
for _, v := range val {
|
||||
req.Header.Set(key, v)
|
||||
}
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil && err.(*net.AddrError).Err == "missing port in address" { //nolint:errorlint, forcetypeassert // overlinting
|
||||
r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80")
|
||||
}
|
||||
remoteAddr, err := net.ResolveTCPAddr("tcp", r.RemoteAddr)
|
||||
if err != nil {
|
||||
http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// New fasthttp Ctx
|
||||
var fctx fasthttp.RequestCtx
|
||||
fctx.Init(req, remoteAddr, nil)
|
||||
if len(h) > 0 {
|
||||
// New fiber Ctx
|
||||
ctx := app.AcquireCtx(&fctx)
|
||||
defer app.ReleaseCtx(ctx)
|
||||
// Execute fiber Ctx
|
||||
err := h[0](ctx)
|
||||
if err != nil {
|
||||
_ = app.Config().ErrorHandler(ctx, err) //nolint:errcheck // not needed
|
||||
}
|
||||
} else {
|
||||
// Execute fasthttp Ctx though app.Handler
|
||||
app.Handler()(&fctx)
|
||||
}
|
||||
|
||||
// Convert fasthttp Ctx > net/http
|
||||
fctx.Response.Header.VisitAll(func(k, v []byte) {
|
||||
w.Header().Add(string(k), string(v))
|
||||
})
|
||||
w.WriteHeader(fctx.Response.StatusCode())
|
||||
_, _ = w.Write(fctx.Response.Body()) //nolint:errcheck // not needed
|
||||
}
|
||||
}
|
|
@ -0,0 +1,462 @@
|
|||
//nolint:bodyclose, contextcheck, revive // Much easier to just ignore memory leaks in tests
|
||||
package adaptor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
func Test_HTTPHandler(t *testing.T) {
|
||||
expectedMethod := fiber.MethodPost
|
||||
expectedProto := "HTTP/1.1"
|
||||
expectedProtoMajor := 1
|
||||
expectedProtoMinor := 1
|
||||
expectedRequestURI := "/foo/bar?baz=123"
|
||||
expectedBody := "body 123 foo bar baz"
|
||||
expectedContentLength := len(expectedBody)
|
||||
expectedHost := "foobar.com"
|
||||
expectedRemoteAddr := "1.2.3.4:6789"
|
||||
expectedHeader := map[string]string{
|
||||
"Foo-Bar": "baz",
|
||||
"Abc": "defg",
|
||||
"XXX-Remote-Addr": "123.43.4543.345",
|
||||
}
|
||||
expectedURL, err := url.ParseRequestURI(expectedRequestURI)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
expectedContextKey := "contextKey"
|
||||
expectedContextValue := "contextValue"
|
||||
|
||||
callsCount := 0
|
||||
nethttpH := func(w http.ResponseWriter, r *http.Request) {
|
||||
callsCount++
|
||||
if r.Method != expectedMethod {
|
||||
t.Fatalf("unexpected method %q. Expecting %q", r.Method, expectedMethod)
|
||||
}
|
||||
if r.Proto != expectedProto {
|
||||
t.Fatalf("unexpected proto %q. Expecting %q", r.Proto, expectedProto)
|
||||
}
|
||||
if r.ProtoMajor != expectedProtoMajor {
|
||||
t.Fatalf("unexpected protoMajor %d. Expecting %d", r.ProtoMajor, expectedProtoMajor)
|
||||
}
|
||||
if r.ProtoMinor != expectedProtoMinor {
|
||||
t.Fatalf("unexpected protoMinor %d. Expecting %d", r.ProtoMinor, expectedProtoMinor)
|
||||
}
|
||||
if r.RequestURI != expectedRequestURI {
|
||||
t.Fatalf("unexpected requestURI %q. Expecting %q", r.RequestURI, expectedRequestURI)
|
||||
}
|
||||
if r.ContentLength != int64(expectedContentLength) {
|
||||
t.Fatalf("unexpected contentLength %d. Expecting %d", r.ContentLength, expectedContentLength)
|
||||
}
|
||||
if len(r.TransferEncoding) != 0 {
|
||||
t.Fatalf("unexpected transferEncoding %q. Expecting []", r.TransferEncoding)
|
||||
}
|
||||
if r.Host != expectedHost {
|
||||
t.Fatalf("unexpected host %q. Expecting %q", r.Host, expectedHost)
|
||||
}
|
||||
if r.RemoteAddr != expectedRemoteAddr {
|
||||
t.Fatalf("unexpected remoteAddr %q. Expecting %q", r.RemoteAddr, expectedRemoteAddr)
|
||||
}
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error when reading request body: %s", err)
|
||||
}
|
||||
if string(body) != expectedBody {
|
||||
t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody)
|
||||
}
|
||||
if !reflect.DeepEqual(r.URL, expectedURL) {
|
||||
t.Fatalf("unexpected URL: %#v. Expecting %#v", r.URL, expectedURL)
|
||||
}
|
||||
if r.Context().Value(expectedContextKey) != expectedContextValue {
|
||||
t.Fatalf("unexpected context value for key %q. Expecting %q", expectedContextKey, expectedContextValue)
|
||||
}
|
||||
|
||||
for k, expectedV := range expectedHeader {
|
||||
v := r.Header.Get(k)
|
||||
if v != expectedV {
|
||||
t.Fatalf("unexpected header value %q for key %q. Expecting %q", v, k, expectedV)
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Header1", "value1")
|
||||
w.Header().Set("Header2", "value2")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintf(w, "request body is %q", body)
|
||||
}
|
||||
fiberH := HTTPHandlerFunc(http.HandlerFunc(nethttpH))
|
||||
fiberH = setFiberContextValueMiddleware(fiberH, expectedContextKey, expectedContextValue)
|
||||
|
||||
var fctx fasthttp.RequestCtx
|
||||
var req fasthttp.Request
|
||||
|
||||
req.Header.SetMethod(expectedMethod)
|
||||
req.SetRequestURI(expectedRequestURI)
|
||||
req.Header.SetHost(expectedHost)
|
||||
req.BodyWriter().Write([]byte(expectedBody)) //nolint:errcheck, gosec // not needed
|
||||
for k, v := range expectedHeader {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
remoteAddr, err := net.ResolveTCPAddr("tcp", expectedRemoteAddr)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
fctx.Init(&req, remoteAddr, nil)
|
||||
app := fiber.New()
|
||||
ctx := app.AcquireCtx(&fctx)
|
||||
defer app.ReleaseCtx(ctx)
|
||||
|
||||
err = fiberH(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if callsCount != 1 {
|
||||
t.Fatalf("unexpected callsCount: %d. Expecting 1", callsCount)
|
||||
}
|
||||
|
||||
resp := &fctx.Response
|
||||
if resp.StatusCode() != fiber.StatusBadRequest {
|
||||
t.Fatalf("unexpected statusCode: %d. Expecting %d", resp.StatusCode(), fiber.StatusBadRequest)
|
||||
}
|
||||
if string(resp.Header.Peek("Header1")) != "value1" {
|
||||
t.Fatalf("unexpected header value: %q. Expecting %q", resp.Header.Peek("Header1"), "value1")
|
||||
}
|
||||
if string(resp.Header.Peek("Header2")) != "value2" {
|
||||
t.Fatalf("unexpected header value: %q. Expecting %q", resp.Header.Peek("Header2"), "value2")
|
||||
}
|
||||
expectedResponseBody := fmt.Sprintf("request body is %q", expectedBody)
|
||||
if string(resp.Body()) != expectedResponseBody {
|
||||
t.Fatalf("unexpected response body %q. Expecting %q", resp.Body(), expectedResponseBody)
|
||||
}
|
||||
}
|
||||
|
||||
type contextKey string
|
||||
|
||||
func (c contextKey) String() string {
|
||||
return "test-" + string(c)
|
||||
}
|
||||
|
||||
var (
|
||||
TestContextKey = contextKey("TestContextKey")
|
||||
TestContextSecondKey = contextKey("TestContextSecondKey")
|
||||
)
|
||||
|
||||
func Test_HTTPMiddleware(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
url string
|
||||
method string
|
||||
statusCode int
|
||||
}{
|
||||
{
|
||||
name: "Should return 200",
|
||||
url: "/",
|
||||
method: "POST",
|
||||
statusCode: 200,
|
||||
},
|
||||
{
|
||||
name: "Should return 405",
|
||||
url: "/",
|
||||
method: "GET",
|
||||
statusCode: 405,
|
||||
},
|
||||
{
|
||||
name: "Should return 400",
|
||||
url: "/unknown",
|
||||
method: "POST",
|
||||
statusCode: 404,
|
||||
},
|
||||
}
|
||||
|
||||
nethttpMW := func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
r = r.WithContext(context.WithValue(r.Context(), TestContextKey, "okay"))
|
||||
r = r.WithContext(context.WithValue(r.Context(), TestContextSecondKey, "not_okay"))
|
||||
r = r.WithContext(context.WithValue(r.Context(), TestContextSecondKey, "okay"))
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
app := fiber.New()
|
||||
app.Use(HTTPMiddleware(nethttpMW))
|
||||
app.Post("/", func(c *fiber.Ctx) error {
|
||||
value := c.Context().Value(TestContextKey)
|
||||
val, ok := value.(string)
|
||||
if !ok {
|
||||
t.Error("unexpected error on type-assertion")
|
||||
}
|
||||
if value != nil {
|
||||
c.Set("context_okay", val)
|
||||
}
|
||||
value = c.Context().Value(TestContextSecondKey)
|
||||
if value != nil {
|
||||
val, ok := value.(string)
|
||||
if !ok {
|
||||
t.Error("unexpected error on type-assertion")
|
||||
}
|
||||
c.Set("context_second_okay", val)
|
||||
}
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
for _, tt := range tests {
|
||||
req, err := http.NewRequestWithContext(context.Background(), tt.method, tt.url, nil)
|
||||
if err != nil {
|
||||
t.Fatalf(`%s: %s`, t.Name(), err)
|
||||
}
|
||||
resp, err := app.Test(req)
|
||||
if err != nil {
|
||||
t.Fatalf(`%s: %s`, t.Name(), err)
|
||||
}
|
||||
if resp.StatusCode != tt.statusCode {
|
||||
t.Fatalf(`%s: StatusCode: got %v - expected %v`, t.Name(), resp.StatusCode, tt.statusCode)
|
||||
}
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(context.Background(), fiber.MethodPost, "/", nil)
|
||||
if err != nil {
|
||||
t.Fatalf(`%s: %s`, t.Name(), err)
|
||||
}
|
||||
resp, err := app.Test(req)
|
||||
if err != nil {
|
||||
t.Fatalf(`%s: %s`, t.Name(), err)
|
||||
}
|
||||
if resp.Header.Get("context_okay") != "okay" {
|
||||
t.Fatalf(`%s: Header context_okay: got %v - expected %v`, t.Name(), resp.Header.Get("context_okay"), "okay")
|
||||
}
|
||||
if resp.Header.Get("context_second_okay") != "okay" {
|
||||
t.Fatalf(`%s: Header context_second_okay: got %v - expected %v`, t.Name(), resp.Header.Get("context_second_okay"), "okay")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_FiberHandler(t *testing.T) {
|
||||
testFiberToHandlerFunc(t, false)
|
||||
}
|
||||
|
||||
func Test_FiberApp(t *testing.T) {
|
||||
testFiberToHandlerFunc(t, false, fiber.New())
|
||||
}
|
||||
|
||||
func Test_FiberHandlerDefaultPort(t *testing.T) {
|
||||
testFiberToHandlerFunc(t, true)
|
||||
}
|
||||
|
||||
func Test_FiberAppDefaultPort(t *testing.T) {
|
||||
testFiberToHandlerFunc(t, true, fiber.New())
|
||||
}
|
||||
|
||||
func testFiberToHandlerFunc(t *testing.T, checkDefaultPort bool, app ...*fiber.App) {
|
||||
t.Helper()
|
||||
|
||||
expectedMethod := fiber.MethodPost
|
||||
expectedRequestURI := "/foo/bar?baz=123"
|
||||
expectedBody := "body 123 foo bar baz"
|
||||
expectedContentLength := len(expectedBody)
|
||||
expectedHost := "foobar.com"
|
||||
expectedRemoteAddr := "1.2.3.4:6789"
|
||||
if checkDefaultPort {
|
||||
expectedRemoteAddr = "1.2.3.4:80"
|
||||
}
|
||||
expectedHeader := map[string]string{
|
||||
"Foo-Bar": "baz",
|
||||
"Abc": "defg",
|
||||
"XXX-Remote-Addr": "123.43.4543.345",
|
||||
}
|
||||
expectedURL, err := url.ParseRequestURI(expectedRequestURI)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
callsCount := 0
|
||||
fiberH := func(c *fiber.Ctx) error {
|
||||
callsCount++
|
||||
if c.Method() != expectedMethod {
|
||||
t.Fatalf("unexpected method %q. Expecting %q", c.Method(), expectedMethod)
|
||||
}
|
||||
if string(c.Context().RequestURI()) != expectedRequestURI {
|
||||
t.Fatalf("unexpected requestURI %q. Expecting %q", string(c.Context().RequestURI()), expectedRequestURI)
|
||||
}
|
||||
contentLength := c.Context().Request.Header.ContentLength()
|
||||
if contentLength != expectedContentLength {
|
||||
t.Fatalf("unexpected contentLength %d. Expecting %d", contentLength, expectedContentLength)
|
||||
}
|
||||
if c.Hostname() != expectedHost {
|
||||
t.Fatalf("unexpected host %q. Expecting %q", c.Hostname(), expectedHost)
|
||||
}
|
||||
remoteAddr := c.Context().RemoteAddr().String()
|
||||
if remoteAddr != expectedRemoteAddr {
|
||||
t.Fatalf("unexpected remoteAddr %q. Expecting %q", remoteAddr, expectedRemoteAddr)
|
||||
}
|
||||
body := string(c.Body())
|
||||
if body != expectedBody {
|
||||
t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody)
|
||||
}
|
||||
if c.OriginalURL() != expectedURL.String() {
|
||||
t.Fatalf("unexpected URL: %#v. Expecting %#v", c.OriginalURL(), expectedURL)
|
||||
}
|
||||
|
||||
for k, expectedV := range expectedHeader {
|
||||
v := c.Get(k)
|
||||
if v != expectedV {
|
||||
t.Fatalf("unexpected header value %q for key %q. Expecting %q", v, k, expectedV)
|
||||
}
|
||||
}
|
||||
|
||||
c.Set("Header1", "value1")
|
||||
c.Set("Header2", "value2")
|
||||
c.Status(fiber.StatusBadRequest)
|
||||
_, err := c.Write([]byte(fmt.Sprintf("request body is %q", body)))
|
||||
return err
|
||||
}
|
||||
|
||||
var handlerFunc http.HandlerFunc
|
||||
if len(app) > 0 {
|
||||
app[0].Post("/foo/bar", fiberH)
|
||||
handlerFunc = FiberApp(app[0])
|
||||
} else {
|
||||
handlerFunc = FiberHandlerFunc(fiberH)
|
||||
}
|
||||
|
||||
var r http.Request
|
||||
|
||||
r.Method = expectedMethod
|
||||
r.Body = &netHTTPBody{[]byte(expectedBody)}
|
||||
r.RequestURI = expectedRequestURI
|
||||
r.ContentLength = int64(expectedContentLength)
|
||||
r.Host = expectedHost
|
||||
r.RemoteAddr = expectedRemoteAddr
|
||||
if checkDefaultPort {
|
||||
r.RemoteAddr = "1.2.3.4"
|
||||
}
|
||||
|
||||
hdr := make(http.Header)
|
||||
for k, v := range expectedHeader {
|
||||
hdr.Set(k, v)
|
||||
}
|
||||
r.Header = hdr
|
||||
|
||||
var w netHTTPResponseWriter
|
||||
handlerFunc.ServeHTTP(&w, &r)
|
||||
|
||||
if w.StatusCode() != http.StatusBadRequest {
|
||||
t.Fatalf("unexpected statusCode: %d. Expecting %d", w.StatusCode(), http.StatusBadRequest)
|
||||
}
|
||||
if w.Header().Get("Header1") != "value1" {
|
||||
t.Fatalf("unexpected header value: %q. Expecting %q", w.Header().Get("Header1"), "value1")
|
||||
}
|
||||
if w.Header().Get("Header2") != "value2" {
|
||||
t.Fatalf("unexpected header value: %q. Expecting %q", w.Header().Get("Header2"), "value2")
|
||||
}
|
||||
expectedResponseBody := fmt.Sprintf("request body is %q", expectedBody)
|
||||
if string(w.body) != expectedResponseBody {
|
||||
t.Fatalf("unexpected response body %q. Expecting %q", string(w.body), expectedResponseBody)
|
||||
}
|
||||
}
|
||||
|
||||
func setFiberContextValueMiddleware(next fiber.Handler, key string, value interface{}) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
c.Locals(key, value)
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_FiberHandler_RequestNilBody(t *testing.T) {
|
||||
expectedMethod := fiber.MethodGet
|
||||
expectedRequestURI := "/foo/bar"
|
||||
expectedContentLength := 0
|
||||
|
||||
callsCount := 0
|
||||
fiberH := func(c *fiber.Ctx) error {
|
||||
callsCount++
|
||||
if c.Method() != expectedMethod {
|
||||
t.Fatalf("unexpected method %q. Expecting %q", c.Method(), expectedMethod)
|
||||
}
|
||||
if string(c.Request().RequestURI()) != expectedRequestURI {
|
||||
t.Fatalf("unexpected requestURI %q. Expecting %q", string(c.Request().RequestURI()), expectedRequestURI)
|
||||
}
|
||||
contentLength := c.Request().Header.ContentLength()
|
||||
if contentLength != expectedContentLength {
|
||||
t.Fatalf("unexpected contentLength %d. Expecting %d", contentLength, expectedContentLength)
|
||||
}
|
||||
|
||||
_, err := c.Write([]byte("request body is nil"))
|
||||
return err
|
||||
}
|
||||
nethttpH := FiberHandler(fiberH)
|
||||
|
||||
var r http.Request
|
||||
|
||||
r.Method = expectedMethod
|
||||
r.RequestURI = expectedRequestURI
|
||||
|
||||
var w netHTTPResponseWriter
|
||||
nethttpH.ServeHTTP(&w, &r)
|
||||
|
||||
expectedResponseBody := "request body is nil"
|
||||
if string(w.body) != expectedResponseBody {
|
||||
t.Fatalf("unexpected response body %q. Expecting %q", string(w.body), expectedResponseBody)
|
||||
}
|
||||
}
|
||||
|
||||
type netHTTPBody struct {
|
||||
b []byte
|
||||
}
|
||||
|
||||
func (r *netHTTPBody) Read(p []byte) (int, error) {
|
||||
if len(r.b) == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n := copy(p, r.b)
|
||||
r.b = r.b[n:]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (r *netHTTPBody) Close() error {
|
||||
r.b = r.b[:0]
|
||||
return nil
|
||||
}
|
||||
|
||||
type netHTTPResponseWriter struct {
|
||||
statusCode int
|
||||
h http.Header
|
||||
body []byte
|
||||
}
|
||||
|
||||
func (w *netHTTPResponseWriter) StatusCode() int {
|
||||
if w.statusCode == 0 {
|
||||
return http.StatusOK
|
||||
}
|
||||
return w.statusCode
|
||||
}
|
||||
|
||||
func (w *netHTTPResponseWriter) Header() http.Header {
|
||||
if w.h == nil {
|
||||
w.h = make(http.Header)
|
||||
}
|
||||
return w.h
|
||||
}
|
||||
|
||||
func (w *netHTTPResponseWriter) WriteHeader(statusCode int) {
|
||||
w.statusCode = statusCode
|
||||
}
|
||||
|
||||
func (w *netHTTPResponseWriter) Write(p []byte) (int, error) {
|
||||
w.body = append(w.body, p...)
|
||||
return len(p), nil
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package helmet
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Next defines a function to skip middleware.
|
||||
// Optional. Default: nil
|
||||
Next func(*fiber.Ctx) bool
|
||||
|
||||
// XSSProtection
|
||||
// Optional. Default value "0".
|
||||
XSSProtection string
|
||||
|
||||
// ContentTypeNosniff
|
||||
// Optional. Default value "nosniff".
|
||||
ContentTypeNosniff string
|
||||
|
||||
// XFrameOptions
|
||||
// Optional. Default value "SAMEORIGIN".
|
||||
// Possible values: "SAMEORIGIN", "DENY", "ALLOW-FROM uri"
|
||||
XFrameOptions string
|
||||
|
||||
// HSTSMaxAge
|
||||
// Optional. Default value 0.
|
||||
HSTSMaxAge int
|
||||
|
||||
// HSTSExcludeSubdomains
|
||||
// Optional. Default value false.
|
||||
HSTSExcludeSubdomains bool
|
||||
|
||||
// ContentSecurityPolicy
|
||||
// Optional. Default value "".
|
||||
ContentSecurityPolicy string
|
||||
|
||||
// CSPReportOnly
|
||||
// Optional. Default value false.
|
||||
CSPReportOnly bool
|
||||
|
||||
// HSTSPreloadEnabled
|
||||
// Optional. Default value false.
|
||||
HSTSPreloadEnabled bool
|
||||
|
||||
// ReferrerPolicy
|
||||
// Optional. Default value "ReferrerPolicy".
|
||||
ReferrerPolicy string
|
||||
|
||||
// Permissions-Policy
|
||||
// Optional. Default value "".
|
||||
PermissionPolicy string
|
||||
|
||||
// Cross-Origin-Embedder-Policy
|
||||
// Optional. Default value "require-corp".
|
||||
CrossOriginEmbedderPolicy string
|
||||
|
||||
// Cross-Origin-Opener-Policy
|
||||
// Optional. Default value "same-origin".
|
||||
CrossOriginOpenerPolicy string
|
||||
|
||||
// Cross-Origin-Resource-Policy
|
||||
// Optional. Default value "same-origin".
|
||||
CrossOriginResourcePolicy string
|
||||
|
||||
// Origin-Agent-Cluster
|
||||
// Optional. Default value "?1".
|
||||
OriginAgentCluster string
|
||||
|
||||
// X-DNS-Prefetch-Control
|
||||
// Optional. Default value "off".
|
||||
XDNSPrefetchControl string
|
||||
|
||||
// X-Download-Options
|
||||
// Optional. Default value "noopen".
|
||||
XDownloadOptions string
|
||||
|
||||
// X-Permitted-Cross-Domain-Policies
|
||||
// Optional. Default value "none".
|
||||
XPermittedCrossDomain string
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
XSSProtection: "0",
|
||||
ContentTypeNosniff: "nosniff",
|
||||
XFrameOptions: "SAMEORIGIN",
|
||||
ReferrerPolicy: "no-referrer",
|
||||
CrossOriginEmbedderPolicy: "require-corp",
|
||||
CrossOriginOpenerPolicy: "same-origin",
|
||||
CrossOriginResourcePolicy: "same-origin",
|
||||
OriginAgentCluster: "?1",
|
||||
XDNSPrefetchControl: "off",
|
||||
XDownloadOptions: "noopen",
|
||||
XPermittedCrossDomain: "none",
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return ConfigDefault
|
||||
}
|
||||
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.XSSProtection == "" {
|
||||
cfg.XSSProtection = ConfigDefault.XSSProtection
|
||||
}
|
||||
|
||||
if cfg.ContentTypeNosniff == "" {
|
||||
cfg.ContentTypeNosniff = ConfigDefault.ContentTypeNosniff
|
||||
}
|
||||
|
||||
if cfg.XFrameOptions == "" {
|
||||
cfg.XFrameOptions = ConfigDefault.XFrameOptions
|
||||
}
|
||||
|
||||
if cfg.ReferrerPolicy == "" {
|
||||
cfg.ReferrerPolicy = ConfigDefault.ReferrerPolicy
|
||||
}
|
||||
|
||||
if cfg.CrossOriginEmbedderPolicy == "" {
|
||||
cfg.CrossOriginEmbedderPolicy = ConfigDefault.CrossOriginEmbedderPolicy
|
||||
}
|
||||
|
||||
if cfg.CrossOriginOpenerPolicy == "" {
|
||||
cfg.CrossOriginOpenerPolicy = ConfigDefault.CrossOriginOpenerPolicy
|
||||
}
|
||||
|
||||
if cfg.CrossOriginResourcePolicy == "" {
|
||||
cfg.CrossOriginResourcePolicy = ConfigDefault.CrossOriginResourcePolicy
|
||||
}
|
||||
|
||||
if cfg.OriginAgentCluster == "" {
|
||||
cfg.OriginAgentCluster = ConfigDefault.OriginAgentCluster
|
||||
}
|
||||
|
||||
if cfg.XDNSPrefetchControl == "" {
|
||||
cfg.XDNSPrefetchControl = ConfigDefault.XDNSPrefetchControl
|
||||
}
|
||||
|
||||
if cfg.XDownloadOptions == "" {
|
||||
cfg.XDownloadOptions = ConfigDefault.XDownloadOptions
|
||||
}
|
||||
|
||||
if cfg.XPermittedCrossDomain == "" {
|
||||
cfg.XPermittedCrossDomain = ConfigDefault.XPermittedCrossDomain
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package helmet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// New creates a new middleware handler
|
||||
func New(config ...Config) fiber.Handler {
|
||||
// Init config
|
||||
cfg := configDefault(config...)
|
||||
|
||||
// Return middleware handler
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Next request to skip middleware
|
||||
if cfg.Next != nil && cfg.Next(c) {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Set headers
|
||||
if cfg.XSSProtection != "" {
|
||||
c.Set(fiber.HeaderXXSSProtection, cfg.XSSProtection)
|
||||
}
|
||||
|
||||
if cfg.ContentTypeNosniff != "" {
|
||||
c.Set(fiber.HeaderXContentTypeOptions, cfg.ContentTypeNosniff)
|
||||
}
|
||||
|
||||
if cfg.XFrameOptions != "" {
|
||||
c.Set(fiber.HeaderXFrameOptions, cfg.XFrameOptions)
|
||||
}
|
||||
|
||||
if cfg.CrossOriginEmbedderPolicy != "" {
|
||||
c.Set("Cross-Origin-Embedder-Policy", cfg.CrossOriginEmbedderPolicy)
|
||||
}
|
||||
|
||||
if cfg.CrossOriginOpenerPolicy != "" {
|
||||
c.Set("Cross-Origin-Opener-Policy", cfg.CrossOriginOpenerPolicy)
|
||||
}
|
||||
|
||||
if cfg.CrossOriginResourcePolicy != "" {
|
||||
c.Set("Cross-Origin-Resource-Policy", cfg.CrossOriginResourcePolicy)
|
||||
}
|
||||
|
||||
if cfg.OriginAgentCluster != "" {
|
||||
c.Set("Origin-Agent-Cluster", cfg.OriginAgentCluster)
|
||||
}
|
||||
|
||||
if cfg.ReferrerPolicy != "" {
|
||||
c.Set("Referrer-Policy", cfg.ReferrerPolicy)
|
||||
}
|
||||
|
||||
if cfg.XDNSPrefetchControl != "" {
|
||||
c.Set("X-DNS-Prefetch-Control", cfg.XDNSPrefetchControl)
|
||||
}
|
||||
|
||||
if cfg.XDownloadOptions != "" {
|
||||
c.Set("X-Download-Options", cfg.XDownloadOptions)
|
||||
}
|
||||
|
||||
if cfg.XPermittedCrossDomain != "" {
|
||||
c.Set("X-Permitted-Cross-Domain-Policies", cfg.XPermittedCrossDomain)
|
||||
}
|
||||
|
||||
// Handle HSTS headers
|
||||
if c.Protocol() == "https" && cfg.HSTSMaxAge != 0 {
|
||||
subdomains := ""
|
||||
if !cfg.HSTSExcludeSubdomains {
|
||||
subdomains = "; includeSubDomains"
|
||||
}
|
||||
if cfg.HSTSPreloadEnabled {
|
||||
subdomains = fmt.Sprintf("%s; preload", subdomains)
|
||||
}
|
||||
c.Set(fiber.HeaderStrictTransportSecurity, fmt.Sprintf("max-age=%d%s", cfg.HSTSMaxAge, subdomains))
|
||||
}
|
||||
|
||||
// Handle Content-Security-Policy headers
|
||||
if cfg.ContentSecurityPolicy != "" {
|
||||
if cfg.CSPReportOnly {
|
||||
c.Set(fiber.HeaderContentSecurityPolicyReportOnly, cfg.ContentSecurityPolicy)
|
||||
} else {
|
||||
c.Set(fiber.HeaderContentSecurityPolicy, cfg.ContentSecurityPolicy)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Permissions-Policy headers
|
||||
if cfg.PermissionPolicy != "" {
|
||||
c.Set(fiber.HeaderPermissionsPolicy, cfg.PermissionPolicy)
|
||||
}
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
package helmet
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
)
|
||||
|
||||
func Test_Default(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New())
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, "0", resp.Header.Get(fiber.HeaderXXSSProtection))
|
||||
utils.AssertEqual(t, "nosniff", resp.Header.Get(fiber.HeaderXContentTypeOptions))
|
||||
utils.AssertEqual(t, "SAMEORIGIN", resp.Header.Get(fiber.HeaderXFrameOptions))
|
||||
utils.AssertEqual(t, "", resp.Header.Get(fiber.HeaderContentSecurityPolicy))
|
||||
utils.AssertEqual(t, "no-referrer", resp.Header.Get(fiber.HeaderReferrerPolicy))
|
||||
utils.AssertEqual(t, "", resp.Header.Get(fiber.HeaderPermissionsPolicy))
|
||||
utils.AssertEqual(t, "require-corp", resp.Header.Get("Cross-Origin-Embedder-Policy"))
|
||||
utils.AssertEqual(t, "same-origin", resp.Header.Get("Cross-Origin-Opener-Policy"))
|
||||
utils.AssertEqual(t, "same-origin", resp.Header.Get("Cross-Origin-Resource-Policy"))
|
||||
utils.AssertEqual(t, "?1", resp.Header.Get("Origin-Agent-Cluster"))
|
||||
utils.AssertEqual(t, "off", resp.Header.Get("X-DNS-Prefetch-Control"))
|
||||
utils.AssertEqual(t, "noopen", resp.Header.Get("X-Download-Options"))
|
||||
utils.AssertEqual(t, "none", resp.Header.Get("X-Permitted-Cross-Domain-Policies"))
|
||||
}
|
||||
|
||||
func Test_CustomValues_AllHeaders(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
// Custom values for all headers
|
||||
XSSProtection: "0",
|
||||
ContentTypeNosniff: "custom-nosniff",
|
||||
XFrameOptions: "DENY",
|
||||
HSTSExcludeSubdomains: true,
|
||||
ContentSecurityPolicy: "default-src 'none'",
|
||||
CSPReportOnly: true,
|
||||
HSTSPreloadEnabled: true,
|
||||
ReferrerPolicy: "origin",
|
||||
PermissionPolicy: "geolocation=(self)",
|
||||
CrossOriginEmbedderPolicy: "custom-value",
|
||||
CrossOriginOpenerPolicy: "custom-value",
|
||||
CrossOriginResourcePolicy: "custom-value",
|
||||
OriginAgentCluster: "custom-value",
|
||||
XDNSPrefetchControl: "custom-control",
|
||||
XDownloadOptions: "custom-options",
|
||||
XPermittedCrossDomain: "custom-policies",
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
||||
utils.AssertEqual(t, nil, err)
|
||||
// Assertions for custom header values
|
||||
utils.AssertEqual(t, "0", resp.Header.Get(fiber.HeaderXXSSProtection))
|
||||
utils.AssertEqual(t, "custom-nosniff", resp.Header.Get(fiber.HeaderXContentTypeOptions))
|
||||
utils.AssertEqual(t, "DENY", resp.Header.Get(fiber.HeaderXFrameOptions))
|
||||
utils.AssertEqual(t, "default-src 'none'", resp.Header.Get(fiber.HeaderContentSecurityPolicyReportOnly))
|
||||
utils.AssertEqual(t, "origin", resp.Header.Get(fiber.HeaderReferrerPolicy))
|
||||
utils.AssertEqual(t, "geolocation=(self)", resp.Header.Get(fiber.HeaderPermissionsPolicy))
|
||||
utils.AssertEqual(t, "custom-value", resp.Header.Get("Cross-Origin-Embedder-Policy"))
|
||||
utils.AssertEqual(t, "custom-value", resp.Header.Get("Cross-Origin-Opener-Policy"))
|
||||
utils.AssertEqual(t, "custom-value", resp.Header.Get("Cross-Origin-Resource-Policy"))
|
||||
utils.AssertEqual(t, "custom-value", resp.Header.Get("Origin-Agent-Cluster"))
|
||||
utils.AssertEqual(t, "custom-control", resp.Header.Get("X-DNS-Prefetch-Control"))
|
||||
utils.AssertEqual(t, "custom-options", resp.Header.Get("X-Download-Options"))
|
||||
utils.AssertEqual(t, "custom-policies", resp.Header.Get("X-Permitted-Cross-Domain-Policies"))
|
||||
}
|
||||
|
||||
func Test_RealWorldValues_AllHeaders(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
// Real-world values for all headers
|
||||
XSSProtection: "0",
|
||||
ContentTypeNosniff: "nosniff",
|
||||
XFrameOptions: "SAMEORIGIN",
|
||||
HSTSExcludeSubdomains: false,
|
||||
ContentSecurityPolicy: "default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests",
|
||||
CSPReportOnly: false,
|
||||
HSTSPreloadEnabled: true,
|
||||
ReferrerPolicy: "no-referrer",
|
||||
PermissionPolicy: "geolocation=(self)",
|
||||
CrossOriginEmbedderPolicy: "require-corp",
|
||||
CrossOriginOpenerPolicy: "same-origin",
|
||||
CrossOriginResourcePolicy: "same-origin",
|
||||
OriginAgentCluster: "?1",
|
||||
XDNSPrefetchControl: "off",
|
||||
XDownloadOptions: "noopen",
|
||||
XPermittedCrossDomain: "none",
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
||||
utils.AssertEqual(t, nil, err)
|
||||
// Assertions for real-world header values
|
||||
utils.AssertEqual(t, "0", resp.Header.Get(fiber.HeaderXXSSProtection))
|
||||
utils.AssertEqual(t, "nosniff", resp.Header.Get(fiber.HeaderXContentTypeOptions))
|
||||
utils.AssertEqual(t, "SAMEORIGIN", resp.Header.Get(fiber.HeaderXFrameOptions))
|
||||
utils.AssertEqual(t, "default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests", resp.Header.Get(fiber.HeaderContentSecurityPolicy))
|
||||
utils.AssertEqual(t, "no-referrer", resp.Header.Get(fiber.HeaderReferrerPolicy))
|
||||
utils.AssertEqual(t, "geolocation=(self)", resp.Header.Get(fiber.HeaderPermissionsPolicy))
|
||||
utils.AssertEqual(t, "require-corp", resp.Header.Get("Cross-Origin-Embedder-Policy"))
|
||||
utils.AssertEqual(t, "same-origin", resp.Header.Get("Cross-Origin-Opener-Policy"))
|
||||
utils.AssertEqual(t, "same-origin", resp.Header.Get("Cross-Origin-Resource-Policy"))
|
||||
utils.AssertEqual(t, "?1", resp.Header.Get("Origin-Agent-Cluster"))
|
||||
utils.AssertEqual(t, "off", resp.Header.Get("X-DNS-Prefetch-Control"))
|
||||
utils.AssertEqual(t, "noopen", resp.Header.Get("X-Download-Options"))
|
||||
utils.AssertEqual(t, "none", resp.Header.Get("X-Permitted-Cross-Domain-Policies"))
|
||||
}
|
||||
|
||||
func Test_Next(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
Next: func(ctx *fiber.Ctx) bool {
|
||||
return ctx.Path() == "/next"
|
||||
},
|
||||
ReferrerPolicy: "no-referrer",
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
app.Get("/next", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Skipped!")
|
||||
})
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, "no-referrer", resp.Header.Get(fiber.HeaderReferrerPolicy))
|
||||
|
||||
resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/next", nil))
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, "", resp.Header.Get(fiber.HeaderReferrerPolicy))
|
||||
}
|
||||
|
||||
func Test_ContentSecurityPolicy(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
ContentSecurityPolicy: "default-src 'none'",
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, "default-src 'none'", resp.Header.Get(fiber.HeaderContentSecurityPolicy))
|
||||
}
|
||||
|
||||
func Test_ContentSecurityPolicyReportOnly(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
ContentSecurityPolicy: "default-src 'none'",
|
||||
CSPReportOnly: true,
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, "default-src 'none'", resp.Header.Get(fiber.HeaderContentSecurityPolicyReportOnly))
|
||||
utils.AssertEqual(t, "", resp.Header.Get(fiber.HeaderContentSecurityPolicy))
|
||||
}
|
||||
|
||||
func Test_PermissionsPolicy(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
PermissionPolicy: "microphone=()",
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, "microphone=()", resp.Header.Get(fiber.HeaderPermissionsPolicy))
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package keyauth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Next defines a function to skip middleware.
|
||||
// Optional. Default: nil
|
||||
Next func(*fiber.Ctx) bool
|
||||
|
||||
// SuccessHandler defines a function which is executed for a valid key.
|
||||
// Optional. Default: nil
|
||||
SuccessHandler fiber.Handler
|
||||
|
||||
// ErrorHandler defines a function which is executed for an invalid key.
|
||||
// It may be used to define a custom error.
|
||||
// Optional. Default: 401 Invalid or expired key
|
||||
ErrorHandler fiber.ErrorHandler
|
||||
|
||||
// KeyLookup is a string in the form of "<source>:<name>" that is used
|
||||
// to extract key from the request.
|
||||
// Optional. Default value "header:Authorization".
|
||||
// Possible values:
|
||||
// - "header:<name>"
|
||||
// - "query:<name>"
|
||||
// - "form:<name>"
|
||||
// - "param:<name>"
|
||||
// - "cookie:<name>"
|
||||
KeyLookup string
|
||||
|
||||
// AuthScheme to be used in the Authorization header.
|
||||
// Optional. Default value "Bearer".
|
||||
AuthScheme string
|
||||
|
||||
// Validator is a function to validate key.
|
||||
Validator func(*fiber.Ctx, string) (bool, error)
|
||||
|
||||
// Context key to store the bearertoken from the token into context.
|
||||
// Optional. Default: "token".
|
||||
ContextKey string
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
SuccessHandler: func(c *fiber.Ctx) error {
|
||||
return c.Next()
|
||||
},
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
if errors.Is(err, ErrMissingOrMalformedAPIKey) {
|
||||
return c.Status(fiber.StatusUnauthorized).SendString(err.Error())
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).SendString("Invalid or expired API Key")
|
||||
},
|
||||
KeyLookup: "header:" + fiber.HeaderAuthorization,
|
||||
AuthScheme: "Bearer",
|
||||
ContextKey: "token",
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return ConfigDefault
|
||||
}
|
||||
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.SuccessHandler == nil {
|
||||
cfg.SuccessHandler = ConfigDefault.SuccessHandler
|
||||
}
|
||||
if cfg.ErrorHandler == nil {
|
||||
cfg.ErrorHandler = ConfigDefault.ErrorHandler
|
||||
}
|
||||
if cfg.KeyLookup == "" {
|
||||
cfg.KeyLookup = ConfigDefault.KeyLookup
|
||||
// set AuthScheme as "Bearer" only if KeyLookup is set to default.
|
||||
if cfg.AuthScheme == "" {
|
||||
cfg.AuthScheme = ConfigDefault.AuthScheme
|
||||
}
|
||||
}
|
||||
if cfg.Validator == nil {
|
||||
panic("fiber: keyauth middleware requires a validator function")
|
||||
}
|
||||
if cfg.ContextKey == "" {
|
||||
cfg.ContextKey = ConfigDefault.ContextKey
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
// Special thanks to Echo: https://github.com/labstack/echo/blob/master/middleware/key_auth.go
|
||||
package keyauth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// When there is no request of the key thrown ErrMissingOrMalformedAPIKey
|
||||
var ErrMissingOrMalformedAPIKey = errors.New("missing or malformed API Key")
|
||||
|
||||
const (
|
||||
query = "query"
|
||||
form = "form"
|
||||
param = "param"
|
||||
cookie = "cookie"
|
||||
)
|
||||
|
||||
// New creates a new middleware handler
|
||||
func New(config ...Config) fiber.Handler {
|
||||
// Init config
|
||||
cfg := configDefault(config...)
|
||||
|
||||
// Initialize
|
||||
parts := strings.Split(cfg.KeyLookup, ":")
|
||||
extractor := keyFromHeader(parts[1], cfg.AuthScheme)
|
||||
switch parts[0] {
|
||||
case query:
|
||||
extractor = keyFromQuery(parts[1])
|
||||
case form:
|
||||
extractor = keyFromForm(parts[1])
|
||||
case param:
|
||||
extractor = keyFromParam(parts[1])
|
||||
case cookie:
|
||||
extractor = keyFromCookie(parts[1])
|
||||
}
|
||||
|
||||
// Return middleware handler
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Filter request to skip middleware
|
||||
if cfg.Next != nil && cfg.Next(c) {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Extract and verify key
|
||||
key, err := extractor(c)
|
||||
if err != nil {
|
||||
return cfg.ErrorHandler(c, err)
|
||||
}
|
||||
|
||||
valid, err := cfg.Validator(c, key)
|
||||
|
||||
if err == nil && valid {
|
||||
c.Locals(cfg.ContextKey, key)
|
||||
return cfg.SuccessHandler(c)
|
||||
}
|
||||
return cfg.ErrorHandler(c, err)
|
||||
}
|
||||
}
|
||||
|
||||
// keyFromHeader returns a function that extracts api key from the request header.
|
||||
func keyFromHeader(header, authScheme string) func(c *fiber.Ctx) (string, error) {
|
||||
return func(c *fiber.Ctx) (string, error) {
|
||||
auth := c.Get(header)
|
||||
l := len(authScheme)
|
||||
if len(auth) > 0 && l == 0 {
|
||||
return auth, nil
|
||||
}
|
||||
if len(auth) > l+1 && auth[:l] == authScheme {
|
||||
return auth[l+1:], nil
|
||||
}
|
||||
return "", ErrMissingOrMalformedAPIKey
|
||||
}
|
||||
}
|
||||
|
||||
// keyFromQuery returns a function that extracts api key from the query string.
|
||||
func keyFromQuery(param string) func(c *fiber.Ctx) (string, error) {
|
||||
return func(c *fiber.Ctx) (string, error) {
|
||||
key := c.Query(param)
|
||||
if key == "" {
|
||||
return "", ErrMissingOrMalformedAPIKey
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
}
|
||||
|
||||
// keyFromForm returns a function that extracts api key from the form.
|
||||
func keyFromForm(param string) func(c *fiber.Ctx) (string, error) {
|
||||
return func(c *fiber.Ctx) (string, error) {
|
||||
key := c.FormValue(param)
|
||||
if key == "" {
|
||||
return "", ErrMissingOrMalformedAPIKey
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
}
|
||||
|
||||
// keyFromParam returns a function that extracts api key from the url param string.
|
||||
func keyFromParam(param string) func(c *fiber.Ctx) (string, error) {
|
||||
return func(c *fiber.Ctx) (string, error) {
|
||||
key, err := url.PathUnescape(c.Params(param))
|
||||
if err != nil {
|
||||
return "", ErrMissingOrMalformedAPIKey
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
}
|
||||
|
||||
// keyFromCookie returns a function that extracts api key from the named cookie.
|
||||
func keyFromCookie(name string) func(c *fiber.Ctx) (string, error) {
|
||||
return func(c *fiber.Ctx) (string, error) {
|
||||
key := c.Cookies(name)
|
||||
if key == "" {
|
||||
return "", ErrMissingOrMalformedAPIKey
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,461 @@
|
|||
//nolint:bodyclose // Much easier to just ignore memory leaks in tests
|
||||
package keyauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
)
|
||||
|
||||
const CorrectKey = "specials: !$%,.#\"!?~`<>@$^*(){}[]|/\\123"
|
||||
|
||||
func TestAuthSources(t *testing.T) {
|
||||
// define test cases
|
||||
testSources := []string{"header", "cookie", "query", "param", "form"}
|
||||
|
||||
tests := []struct {
|
||||
route string
|
||||
authTokenName string
|
||||
description string
|
||||
APIKey string
|
||||
expectedCode int
|
||||
expectedBody string
|
||||
}{
|
||||
{
|
||||
route: "/",
|
||||
authTokenName: "access_token",
|
||||
description: "auth with correct key",
|
||||
APIKey: CorrectKey,
|
||||
expectedCode: 200,
|
||||
expectedBody: "Success!",
|
||||
},
|
||||
{
|
||||
route: "/",
|
||||
authTokenName: "access_token",
|
||||
description: "auth with no key",
|
||||
APIKey: "",
|
||||
expectedCode: 401, // 404 in case of param authentication
|
||||
expectedBody: "missing or malformed API Key",
|
||||
},
|
||||
{
|
||||
route: "/",
|
||||
authTokenName: "access_token",
|
||||
description: "auth with wrong key",
|
||||
APIKey: "WRONGKEY",
|
||||
expectedCode: 401,
|
||||
expectedBody: "missing or malformed API Key",
|
||||
},
|
||||
}
|
||||
|
||||
for _, authSource := range testSources {
|
||||
t.Run(authSource, func(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
// setup the fiber endpoint
|
||||
// note that if UnescapePath: false (the default)
|
||||
// escaped characters (such as `\"`) will not be handled correctly in the tests
|
||||
app := fiber.New(fiber.Config{UnescapePath: true})
|
||||
|
||||
authMiddleware := New(Config{
|
||||
KeyLookup: authSource + ":" + test.authTokenName,
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
if key == CorrectKey {
|
||||
return true, nil
|
||||
}
|
||||
return false, ErrMissingOrMalformedAPIKey
|
||||
},
|
||||
})
|
||||
|
||||
var route string
|
||||
if authSource == param {
|
||||
route = test.route + ":" + test.authTokenName
|
||||
app.Use(route, authMiddleware)
|
||||
} else {
|
||||
route = test.route
|
||||
app.Use(authMiddleware)
|
||||
}
|
||||
|
||||
app.Get(route, func(c *fiber.Ctx) error {
|
||||
return c.SendString("Success!")
|
||||
})
|
||||
|
||||
// construct the test HTTP request
|
||||
var req *http.Request
|
||||
req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, test.route, nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// setup the apikey for the different auth schemes
|
||||
if authSource == "header" {
|
||||
req.Header.Set(test.authTokenName, test.APIKey)
|
||||
} else if authSource == "cookie" {
|
||||
req.Header.Set("Cookie", test.authTokenName+"="+test.APIKey)
|
||||
} else if authSource == "query" || authSource == "form" {
|
||||
q := req.URL.Query()
|
||||
q.Add(test.authTokenName, test.APIKey)
|
||||
req.URL.RawQuery = q.Encode()
|
||||
} else if authSource == "param" {
|
||||
r := req.URL.Path
|
||||
r += url.PathEscape(test.APIKey)
|
||||
req.URL.Path = r
|
||||
}
|
||||
|
||||
res, err := app.Test(req, -1)
|
||||
|
||||
utils.AssertEqual(t, nil, err, test.description)
|
||||
|
||||
// test the body of the request
|
||||
body, err := io.ReadAll(res.Body)
|
||||
// for param authentication, the route would be /:access_token
|
||||
// when the access_token is empty, it leads to a 404 (not found)
|
||||
// not a 401 (auth error)
|
||||
if authSource == "param" && test.APIKey == "" {
|
||||
test.expectedCode = 404
|
||||
test.expectedBody = "Cannot GET /"
|
||||
}
|
||||
utils.AssertEqual(t, test.expectedCode, res.StatusCode, test.description)
|
||||
|
||||
// body
|
||||
utils.AssertEqual(t, nil, err, test.description)
|
||||
utils.AssertEqual(t, test.expectedBody, string(body), test.description)
|
||||
|
||||
err = res.Body.Close()
|
||||
utils.AssertEqual(t, err, nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleKeyAuth(t *testing.T) {
|
||||
// setup the fiber endpoint
|
||||
app := fiber.New()
|
||||
|
||||
// setup keyauth for /auth1
|
||||
app.Use(New(Config{
|
||||
Next: func(c *fiber.Ctx) bool {
|
||||
return c.OriginalURL() != "/auth1"
|
||||
},
|
||||
KeyLookup: "header:key",
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
if key == "password1" {
|
||||
return true, nil
|
||||
}
|
||||
return false, ErrMissingOrMalformedAPIKey
|
||||
},
|
||||
}))
|
||||
|
||||
// setup keyauth for /auth2
|
||||
app.Use(New(Config{
|
||||
Next: func(c *fiber.Ctx) bool {
|
||||
return c.OriginalURL() != "/auth2"
|
||||
},
|
||||
KeyLookup: "header:key",
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
if key == "password2" {
|
||||
return true, nil
|
||||
}
|
||||
return false, ErrMissingOrMalformedAPIKey
|
||||
},
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("No auth needed!")
|
||||
})
|
||||
|
||||
app.Get("/auth1", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated for auth1!")
|
||||
})
|
||||
|
||||
app.Get("/auth2", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated for auth2!")
|
||||
})
|
||||
|
||||
// define test cases
|
||||
tests := []struct {
|
||||
route string
|
||||
description string
|
||||
APIKey string
|
||||
expectedCode int
|
||||
expectedBody string
|
||||
}{
|
||||
// No auth needed for /
|
||||
{
|
||||
route: "/",
|
||||
description: "No password needed",
|
||||
APIKey: "",
|
||||
expectedCode: 200,
|
||||
expectedBody: "No auth needed!",
|
||||
},
|
||||
|
||||
// auth needed for auth1
|
||||
{
|
||||
route: "/auth1",
|
||||
description: "Normal Authentication Case",
|
||||
APIKey: "password1",
|
||||
expectedCode: 200,
|
||||
expectedBody: "Successfully authenticated for auth1!",
|
||||
},
|
||||
{
|
||||
route: "/auth1",
|
||||
description: "Wrong API Key",
|
||||
APIKey: "WRONG KEY",
|
||||
expectedCode: 401,
|
||||
expectedBody: "missing or malformed API Key",
|
||||
},
|
||||
{
|
||||
route: "/auth1",
|
||||
description: "Wrong API Key",
|
||||
APIKey: "", // NO KEY
|
||||
expectedCode: 401,
|
||||
expectedBody: "missing or malformed API Key",
|
||||
},
|
||||
|
||||
// Auth 2 has a different password
|
||||
{
|
||||
route: "/auth2",
|
||||
description: "Normal Authentication Case for auth2",
|
||||
APIKey: "password2",
|
||||
expectedCode: 200,
|
||||
expectedBody: "Successfully authenticated for auth2!",
|
||||
},
|
||||
{
|
||||
route: "/auth2",
|
||||
description: "Wrong API Key",
|
||||
APIKey: "WRONG KEY",
|
||||
expectedCode: 401,
|
||||
expectedBody: "missing or malformed API Key",
|
||||
},
|
||||
{
|
||||
route: "/auth2",
|
||||
description: "Wrong API Key",
|
||||
APIKey: "", // NO KEY
|
||||
expectedCode: 401,
|
||||
expectedBody: "missing or malformed API Key",
|
||||
},
|
||||
}
|
||||
|
||||
// run the tests
|
||||
for _, test := range tests {
|
||||
var req *http.Request
|
||||
req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, test.route, nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
if test.APIKey != "" {
|
||||
req.Header.Set("key", test.APIKey)
|
||||
}
|
||||
|
||||
res, err := app.Test(req, -1)
|
||||
|
||||
utils.AssertEqual(t, nil, err, test.description)
|
||||
|
||||
// test the body of the request
|
||||
body, err := io.ReadAll(res.Body)
|
||||
utils.AssertEqual(t, test.expectedCode, res.StatusCode, test.description)
|
||||
|
||||
// body
|
||||
utils.AssertEqual(t, nil, err, test.description)
|
||||
utils.AssertEqual(t, test.expectedBody, string(body), test.description)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomSuccessAndFailureHandlers(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
SuccessHandler: func(c *fiber.Ctx) error {
|
||||
return c.Status(fiber.StatusOK).SendString("API key is valid and request was handled by custom success handler")
|
||||
},
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
return c.Status(fiber.StatusUnauthorized).SendString("API key is invalid and request was handled by custom error handler")
|
||||
},
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
if key == CorrectKey {
|
||||
return true, nil
|
||||
}
|
||||
return false, ErrMissingOrMalformedAPIKey
|
||||
},
|
||||
}))
|
||||
|
||||
// Define a test handler that should not be called
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
t.Error("Test handler should not be called")
|
||||
return nil
|
||||
})
|
||||
|
||||
// Create a request without an API key and send it to the app
|
||||
res, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Read the response body into a string
|
||||
body, err := io.ReadAll(res.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Check that the response has the expected status code and body
|
||||
utils.AssertEqual(t, res.StatusCode, http.StatusUnauthorized)
|
||||
utils.AssertEqual(t, string(body), "API key is invalid and request was handled by custom error handler")
|
||||
|
||||
// Create a request with a valid API key in the Authorization header
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", CorrectKey))
|
||||
|
||||
// Send the request to the app
|
||||
res, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Read the response body into a string
|
||||
body, err = io.ReadAll(res.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Check that the response has the expected status code and body
|
||||
utils.AssertEqual(t, res.StatusCode, http.StatusOK)
|
||||
utils.AssertEqual(t, string(body), "API key is valid and request was handled by custom success handler")
|
||||
}
|
||||
|
||||
func TestCustomNextFunc(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
Next: func(c *fiber.Ctx) bool {
|
||||
return c.Path() == "/allowed"
|
||||
},
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
if key == CorrectKey {
|
||||
return true, nil
|
||||
}
|
||||
return false, ErrMissingOrMalformedAPIKey
|
||||
},
|
||||
}))
|
||||
|
||||
// Define a test handler
|
||||
app.Get("/allowed", func(c *fiber.Ctx) error {
|
||||
return c.SendString("API key is valid and request was allowed by custom filter")
|
||||
})
|
||||
|
||||
// Create a request with the "/allowed" path and send it to the app
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/allowed", nil)
|
||||
res, err := app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Read the response body into a string
|
||||
body, err := io.ReadAll(res.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Check that the response has the expected status code and body
|
||||
utils.AssertEqual(t, res.StatusCode, http.StatusOK)
|
||||
utils.AssertEqual(t, string(body), "API key is valid and request was allowed by custom filter")
|
||||
|
||||
// Create a request with a different path and send it to the app without correct key
|
||||
req = httptest.NewRequest(fiber.MethodGet, "/not-allowed", nil)
|
||||
res, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Read the response body into a string
|
||||
body, err = io.ReadAll(res.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Check that the response has the expected status code and body
|
||||
utils.AssertEqual(t, res.StatusCode, http.StatusUnauthorized)
|
||||
utils.AssertEqual(t, string(body), ErrMissingOrMalformedAPIKey.Error())
|
||||
|
||||
// Create a request with a different path and send it to the app with correct key
|
||||
req = httptest.NewRequest(fiber.MethodGet, "/not-allowed", nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Basic %s", CorrectKey))
|
||||
|
||||
res, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Read the response body into a string
|
||||
body, err = io.ReadAll(res.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Check that the response has the expected status code and body
|
||||
utils.AssertEqual(t, res.StatusCode, http.StatusUnauthorized)
|
||||
utils.AssertEqual(t, string(body), ErrMissingOrMalformedAPIKey.Error())
|
||||
}
|
||||
|
||||
func TestAuthSchemeToken(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
AuthScheme: "Token",
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
if key == CorrectKey {
|
||||
return true, nil
|
||||
}
|
||||
return false, ErrMissingOrMalformedAPIKey
|
||||
},
|
||||
}))
|
||||
|
||||
// Define a test handler
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("API key is valid")
|
||||
})
|
||||
|
||||
// Create a request with a valid API key in the "Token" Authorization header
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Token %s", CorrectKey))
|
||||
|
||||
// Send the request to the app
|
||||
res, err := app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Read the response body into a string
|
||||
body, err := io.ReadAll(res.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Check that the response has the expected status code and body
|
||||
utils.AssertEqual(t, res.StatusCode, http.StatusOK)
|
||||
utils.AssertEqual(t, string(body), "API key is valid")
|
||||
}
|
||||
|
||||
func TestAuthSchemeBasic(t *testing.T) {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
KeyLookup: "header:Authorization",
|
||||
AuthScheme: "Basic",
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
if key == CorrectKey {
|
||||
return true, nil
|
||||
}
|
||||
return false, ErrMissingOrMalformedAPIKey
|
||||
},
|
||||
}))
|
||||
|
||||
// Define a test handler
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("API key is valid")
|
||||
})
|
||||
|
||||
// Create a request without an API key and Send the request to the app
|
||||
res, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Read the response body into a string
|
||||
body, err := io.ReadAll(res.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Check that the response has the expected status code and body
|
||||
utils.AssertEqual(t, res.StatusCode, http.StatusUnauthorized)
|
||||
utils.AssertEqual(t, string(body), ErrMissingOrMalformedAPIKey.Error())
|
||||
|
||||
// Create a request with a valid API key in the "Authorization" header using the "Basic" scheme
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Basic %s", CorrectKey))
|
||||
|
||||
// Send the request to the app
|
||||
res, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Read the response body into a string
|
||||
body, err = io.ReadAll(res.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
// Check that the response has the expected status code and body
|
||||
utils.AssertEqual(t, res.StatusCode, http.StatusOK)
|
||||
utils.AssertEqual(t, string(body), "API key is valid")
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Filter defines a function to skip middleware.
|
||||
// Optional. Default: nil
|
||||
Next func(*fiber.Ctx) bool
|
||||
|
||||
// Rules defines the URL path rewrite rules. The values captured in asterisk can be
|
||||
// retrieved by index e.g. $1, $2 and so on.
|
||||
// Required. Example:
|
||||
// "/old": "/new",
|
||||
// "/api/*": "/$1",
|
||||
// "/js/*": "/public/javascripts/$1",
|
||||
// "/users/*/orders/*": "/user/$1/order/$2",
|
||||
Rules map[string]string
|
||||
|
||||
// The status code when redirecting
|
||||
// This is ignored if Redirect is disabled
|
||||
// Optional. Default: 302 Temporary Redirect
|
||||
StatusCode int
|
||||
|
||||
rulesRegex map[*regexp.Regexp]string
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
StatusCode: fiber.StatusFound,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return ConfigDefault
|
||||
}
|
||||
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.StatusCode == 0 {
|
||||
cfg.StatusCode = ConfigDefault.StatusCode
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// New creates a new middleware handler
|
||||
func New(config ...Config) fiber.Handler {
|
||||
cfg := configDefault(config...)
|
||||
|
||||
// Initialize
|
||||
cfg.rulesRegex = map[*regexp.Regexp]string{}
|
||||
for k, v := range cfg.Rules {
|
||||
k = strings.ReplaceAll(k, "*", "(.*)")
|
||||
k += "$"
|
||||
cfg.rulesRegex[regexp.MustCompile(k)] = v
|
||||
}
|
||||
|
||||
// Middleware function
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Next request to skip middleware
|
||||
if cfg.Next != nil && cfg.Next(c) {
|
||||
return c.Next()
|
||||
}
|
||||
// Rewrite
|
||||
for k, v := range cfg.rulesRegex {
|
||||
replacer := captureTokens(k, c.Path())
|
||||
if replacer != nil {
|
||||
return c.Redirect(replacer.Replace(v), cfg.StatusCode)
|
||||
}
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/labstack/echo/blob/master/middleware/rewrite.go
|
||||
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
|
||||
if len(input) > 1 {
|
||||
input = strings.TrimSuffix(input, "/")
|
||||
}
|
||||
groups := pattern.FindAllStringSubmatch(input, -1)
|
||||
if groups == nil {
|
||||
return nil
|
||||
}
|
||||
values := groups[0][1:]
|
||||
replace := make([]string, 2*len(values))
|
||||
for i, v := range values {
|
||||
j := 2 * i
|
||||
replace[j] = "$" + strconv.Itoa(i+1)
|
||||
replace[j+1] = v
|
||||
}
|
||||
return strings.NewReplacer(replace...)
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
//nolint:bodyclose // Much easier to just ignore memory leaks in tests
|
||||
package redirect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
)
|
||||
|
||||
func Test_Redirect(t *testing.T) {
|
||||
app := *fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"/default": "google.com",
|
||||
},
|
||||
StatusCode: fiber.StatusMovedPermanently,
|
||||
}))
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"/default/*": "fiber.wiki",
|
||||
},
|
||||
StatusCode: fiber.StatusTemporaryRedirect,
|
||||
}))
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"/redirect/*": "$1",
|
||||
},
|
||||
StatusCode: fiber.StatusSeeOther,
|
||||
}))
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"/pattern/*": "golang.org",
|
||||
},
|
||||
StatusCode: fiber.StatusFound,
|
||||
}))
|
||||
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"/": "/swagger",
|
||||
},
|
||||
StatusCode: fiber.StatusMovedPermanently,
|
||||
}))
|
||||
|
||||
app.Get("/api/*", func(c *fiber.Ctx) error {
|
||||
return c.SendString("API")
|
||||
})
|
||||
|
||||
app.Get("/new", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
url string
|
||||
redirectTo string
|
||||
statusCode int
|
||||
}{
|
||||
{
|
||||
name: "should be returns status StatusFound without a wildcard",
|
||||
url: "/default",
|
||||
redirectTo: "google.com",
|
||||
statusCode: fiber.StatusMovedPermanently,
|
||||
},
|
||||
{
|
||||
name: "should be returns status StatusTemporaryRedirect using wildcard",
|
||||
url: "/default/xyz",
|
||||
redirectTo: "fiber.wiki",
|
||||
statusCode: fiber.StatusTemporaryRedirect,
|
||||
},
|
||||
{
|
||||
name: "should be returns status StatusSeeOther without set redirectTo to use the default",
|
||||
url: "/redirect/github.com/gofiber/redirect",
|
||||
redirectTo: "github.com/gofiber/redirect",
|
||||
statusCode: fiber.StatusSeeOther,
|
||||
},
|
||||
{
|
||||
name: "should return the status code default",
|
||||
url: "/pattern/xyz",
|
||||
redirectTo: "golang.org",
|
||||
statusCode: fiber.StatusFound,
|
||||
},
|
||||
{
|
||||
name: "access URL without rule",
|
||||
url: "/new",
|
||||
statusCode: fiber.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "redirect to swagger route",
|
||||
url: "/",
|
||||
redirectTo: "/swagger",
|
||||
statusCode: fiber.StatusMovedPermanently,
|
||||
},
|
||||
{
|
||||
name: "no redirect to swagger route",
|
||||
url: "/api/",
|
||||
statusCode: fiber.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "no redirect to swagger route #2",
|
||||
url: "/api/test",
|
||||
statusCode: fiber.StatusOK,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, tt.url, nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
req.Header.Set("Location", "github.com/gofiber/redirect")
|
||||
resp, err := app.Test(req)
|
||||
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, tt.statusCode, resp.StatusCode)
|
||||
utils.AssertEqual(t, tt.redirectTo, resp.Header.Get("Location"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Next(t *testing.T) {
|
||||
// Case 1 : Next function always returns true
|
||||
app := *fiber.New()
|
||||
app.Use(New(Config{
|
||||
Next: func(*fiber.Ctx) bool {
|
||||
return true
|
||||
},
|
||||
Rules: map[string]string{
|
||||
"/default": "google.com",
|
||||
},
|
||||
StatusCode: fiber.StatusMovedPermanently,
|
||||
}))
|
||||
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/default", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err := app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
|
||||
// Case 2 : Next function always returns false
|
||||
app = *fiber.New()
|
||||
app.Use(New(Config{
|
||||
Next: func(*fiber.Ctx) bool {
|
||||
return false
|
||||
},
|
||||
Rules: map[string]string{
|
||||
"/default": "google.com",
|
||||
},
|
||||
StatusCode: fiber.StatusMovedPermanently,
|
||||
}))
|
||||
|
||||
req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/default", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
|
||||
utils.AssertEqual(t, fiber.StatusMovedPermanently, resp.StatusCode)
|
||||
utils.AssertEqual(t, "google.com", resp.Header.Get("Location"))
|
||||
}
|
||||
|
||||
func Test_NoRules(t *testing.T) {
|
||||
// Case 1: No rules with default route defined
|
||||
app := *fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
StatusCode: fiber.StatusMovedPermanently,
|
||||
}))
|
||||
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/default", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err := app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
|
||||
// Case 2: No rules and no default route defined
|
||||
app = *fiber.New()
|
||||
|
||||
app.Use(New(Config{
|
||||
StatusCode: fiber.StatusMovedPermanently,
|
||||
}))
|
||||
|
||||
req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/default", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
|
||||
}
|
||||
|
||||
func Test_DefaultConfig(t *testing.T) {
|
||||
// Case 1: Default config and no default route
|
||||
app := *fiber.New()
|
||||
|
||||
app.Use(New())
|
||||
|
||||
req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/default", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err := app.Test(req)
|
||||
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
|
||||
|
||||
// Case 2: Default config and default route
|
||||
app = *fiber.New()
|
||||
|
||||
app.Use(New())
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/default", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err = app.Test(req)
|
||||
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
}
|
||||
|
||||
func Test_RegexRules(t *testing.T) {
|
||||
// Case 1: Rules regex is empty
|
||||
app := *fiber.New()
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{},
|
||||
StatusCode: fiber.StatusMovedPermanently,
|
||||
}))
|
||||
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/default", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err := app.Test(req)
|
||||
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
|
||||
// Case 2: Rules regex map contains valid regex and well-formed replacement URLs
|
||||
app = *fiber.New()
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"/default": "google.com",
|
||||
},
|
||||
StatusCode: fiber.StatusMovedPermanently,
|
||||
}))
|
||||
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/default", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err = app.Test(req)
|
||||
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusMovedPermanently, resp.StatusCode)
|
||||
utils.AssertEqual(t, "google.com", resp.Header.Get("Location"))
|
||||
|
||||
// Case 3: Test invalid regex throws panic
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Log("Recovered from invalid regex: ", r)
|
||||
}
|
||||
}()
|
||||
|
||||
app = *fiber.New()
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"(": "google.com",
|
||||
},
|
||||
StatusCode: fiber.StatusMovedPermanently,
|
||||
}))
|
||||
t.Error("Expected panic, got nil")
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package rewrite
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Next defines a function to skip middleware.
|
||||
// Optional. Default: nil
|
||||
Next func(*fiber.Ctx) bool
|
||||
|
||||
// Rules defines the URL path rewrite rules. The values captured in asterisk can be
|
||||
// retrieved by index e.g. $1, $2 and so on.
|
||||
// Required. Example:
|
||||
// "/old": "/new",
|
||||
// "/api/*": "/$1",
|
||||
// "/js/*": "/public/javascripts/$1",
|
||||
// "/users/*/orders/*": "/user/$1/order/$2",
|
||||
Rules map[string]string
|
||||
|
||||
rulesRegex map[*regexp.Regexp]string
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return Config{}
|
||||
}
|
||||
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
|
||||
return cfg
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package rewrite
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// New creates a new middleware handler
|
||||
func New(config ...Config) fiber.Handler {
|
||||
cfg := configDefault(config...)
|
||||
|
||||
// Initialize
|
||||
cfg.rulesRegex = map[*regexp.Regexp]string{}
|
||||
for k, v := range cfg.Rules {
|
||||
k = strings.ReplaceAll(k, "*", "(.*)")
|
||||
k += "$"
|
||||
cfg.rulesRegex[regexp.MustCompile(k)] = v
|
||||
}
|
||||
// Middleware function
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Next request to skip middleware
|
||||
if cfg.Next != nil && cfg.Next(c) {
|
||||
return c.Next()
|
||||
}
|
||||
// Rewrite
|
||||
for k, v := range cfg.rulesRegex {
|
||||
replacer := captureTokens(k, c.Path())
|
||||
if replacer != nil {
|
||||
c.Path(replacer.Replace(v))
|
||||
break
|
||||
}
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/labstack/echo/blob/master/middleware/rewrite.go
|
||||
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
|
||||
groups := pattern.FindAllStringSubmatch(input, -1)
|
||||
if groups == nil {
|
||||
return nil
|
||||
}
|
||||
values := groups[0][1:]
|
||||
replace := make([]string, 2*len(values))
|
||||
for i, v := range values {
|
||||
j := 2 * i
|
||||
replace[j] = "$" + strconv.Itoa(i+1)
|
||||
replace[j+1] = v
|
||||
}
|
||||
return strings.NewReplacer(replace...)
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
//nolint:bodyclose // Much easier to just ignore memory leaks in tests
|
||||
package rewrite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
)
|
||||
|
||||
func Test_New(t *testing.T) {
|
||||
// Test with no config
|
||||
m := New()
|
||||
|
||||
if m == nil {
|
||||
t.Error("Expected middleware to be returned, got nil")
|
||||
}
|
||||
|
||||
// Test with config
|
||||
m = New(Config{
|
||||
Rules: map[string]string{
|
||||
"/old": "/new",
|
||||
},
|
||||
})
|
||||
|
||||
if m == nil {
|
||||
t.Error("Expected middleware to be returned, got nil")
|
||||
}
|
||||
|
||||
// Test with full config
|
||||
m = New(Config{
|
||||
Next: func(*fiber.Ctx) bool {
|
||||
return true
|
||||
},
|
||||
Rules: map[string]string{
|
||||
"/old": "/new",
|
||||
},
|
||||
})
|
||||
|
||||
if m == nil {
|
||||
t.Error("Expected middleware to be returned, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Rewrite(t *testing.T) {
|
||||
// Case 1: Next function always returns true
|
||||
app := fiber.New()
|
||||
app.Use(New(Config{
|
||||
Next: func(*fiber.Ctx) bool {
|
||||
return true
|
||||
},
|
||||
Rules: map[string]string{
|
||||
"/old": "/new",
|
||||
},
|
||||
}))
|
||||
|
||||
app.Get("/old", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Rewrite Successful")
|
||||
})
|
||||
|
||||
req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/old", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err := app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
bodyString := string(body)
|
||||
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
utils.AssertEqual(t, "Rewrite Successful", bodyString)
|
||||
|
||||
// Case 2: Next function always returns false
|
||||
app = fiber.New()
|
||||
app.Use(New(Config{
|
||||
Next: func(*fiber.Ctx) bool {
|
||||
return false
|
||||
},
|
||||
Rules: map[string]string{
|
||||
"/old": "/new",
|
||||
},
|
||||
}))
|
||||
|
||||
app.Get("/new", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Rewrite Successful")
|
||||
})
|
||||
|
||||
req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/old", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
body, err = io.ReadAll(resp.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
bodyString = string(body)
|
||||
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
utils.AssertEqual(t, "Rewrite Successful", bodyString)
|
||||
|
||||
// Case 3: check for captured tokens in rewrite rule
|
||||
app = fiber.New()
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"/users/*/orders/*": "/user/$1/order/$2",
|
||||
},
|
||||
}))
|
||||
|
||||
app.Get("/user/:userID/order/:orderID", func(c *fiber.Ctx) error {
|
||||
return c.SendString(fmt.Sprintf("User ID: %s, Order ID: %s", c.Params("userID"), c.Params("orderID")))
|
||||
})
|
||||
|
||||
req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/users/123/orders/456", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
body, err = io.ReadAll(resp.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
bodyString = string(body)
|
||||
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
utils.AssertEqual(t, "User ID: 123, Order ID: 456", bodyString)
|
||||
|
||||
// Case 4: Send non-matching request, handled by default route
|
||||
app = fiber.New()
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"/users/*/orders/*": "/user/$1/order/$2",
|
||||
},
|
||||
}))
|
||||
|
||||
app.Get("/user/:userID/order/:orderID", func(c *fiber.Ctx) error {
|
||||
return c.SendString(fmt.Sprintf("User ID: %s, Order ID: %s", c.Params("userID"), c.Params("orderID")))
|
||||
})
|
||||
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/not-matching-any-rule", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
body, err = io.ReadAll(resp.Body)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
bodyString = string(body)
|
||||
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
utils.AssertEqual(t, "OK", bodyString)
|
||||
|
||||
// Case 4: Send non-matching request, with no default route
|
||||
app = fiber.New()
|
||||
app.Use(New(Config{
|
||||
Rules: map[string]string{
|
||||
"/users/*/orders/*": "/user/$1/order/$2",
|
||||
},
|
||||
}))
|
||||
|
||||
app.Get("/user/:userID/order/:orderID", func(c *fiber.Ctx) error {
|
||||
return c.SendString(fmt.Sprintf("User ID: %s, Order ID: %s", c.Params("userID"), c.Params("orderID")))
|
||||
})
|
||||
|
||||
req, err = http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/not-matching-any-rule", nil)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, err, nil)
|
||||
utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
|
||||
}
|
Loading…
Reference in New Issue