v0.12.0 migrate sqlite3 to psql18, updated auth, deploy docs, account and replay updates
test / test (push) Canceled after 0s
test / test (push) Canceled after 0s
This commit is contained in:
1 parent
5d2be4abb2
commit
d0326b059e
66 files changed
+4016
-2433
No files matched your search
@@ -2,12 +2,12 @@ package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"chess/internal/server/core"
|
||||
"chess/internal/server/service"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/lixenwraith/auth"
|
||||
)
|
||||
|
||||
// TokenValidator validates JWT tokens
|
||||
@@ -16,69 +16,59 @@ type TokenValidator func(token string) (userID string, claims map[string]any, er
|
||||
// AuthRequired enforces JWT authentication for protected endpoints
|
||||
func AuthRequired(validateToken TokenValidator) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
token := extractBearerToken(c.Get("Authorization"))
|
||||
if token == "" {
|
||||
header := c.Get(fiber.HeaderAuthorization)
|
||||
if header == "" {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(core.ErrorResponse{
|
||||
Error: "missing authorization token",
|
||||
Code: core.ErrUnauthorized,
|
||||
})
|
||||
}
|
||||
|
||||
userID, claims, err := validateToken(token)
|
||||
token, err := auth.ParseBearerToken(header)
|
||||
if err != nil {
|
||||
if errors.Is(err, service.ErrStorageDisabled) || errors.Is(err, service.ErrStorageUnavailable) {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(core.ErrorResponse{
|
||||
Error: "authentication storage unavailable", Code: core.ErrStorageUnavailable,
|
||||
})
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(core.ErrorResponse{
|
||||
Error: "invalid or expired token",
|
||||
Code: core.ErrUnauthorized,
|
||||
})
|
||||
return invalidToken(c)
|
||||
}
|
||||
|
||||
c.Locals("userID", userID)
|
||||
if sessionID, ok := claims["session_id"].(string); ok {
|
||||
c.Locals("sessionID", sessionID)
|
||||
}
|
||||
return c.Next()
|
||||
return authenticate(c, validateToken, token)
|
||||
}
|
||||
}
|
||||
|
||||
// OptionalAuth permits an absent token but rejects an invalid token instead of
|
||||
// silently downgrading an intended authenticated request to anonymous access.
|
||||
// OptionalAuth permits an absent Authorization header but rejects a malformed
|
||||
// or invalid one instead of silently downgrading an intended authenticated
|
||||
// request to anonymous access.
|
||||
func OptionalAuth(validateToken TokenValidator) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
token := extractBearerToken(c.Get("Authorization"))
|
||||
if token == "" {
|
||||
header := c.Get(fiber.HeaderAuthorization)
|
||||
if header == "" {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
userID, claims, err := validateToken(token)
|
||||
token, err := auth.ParseBearerToken(header)
|
||||
if err != nil {
|
||||
if errors.Is(err, service.ErrStorageDisabled) || errors.Is(err, service.ErrStorageUnavailable) {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(core.ErrorResponse{
|
||||
Error: "authentication storage unavailable", Code: core.ErrStorageUnavailable,
|
||||
})
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(core.ErrorResponse{
|
||||
Error: "invalid or expired token", Code: core.ErrUnauthorized,
|
||||
return invalidToken(c)
|
||||
}
|
||||
return authenticate(c, validateToken, token)
|
||||
}
|
||||
}
|
||||
|
||||
func authenticate(c *fiber.Ctx, validateToken TokenValidator, token string) error {
|
||||
userID, claims, err := validateToken(token)
|
||||
if err != nil {
|
||||
if errors.Is(err, service.ErrStorageDisabled) || errors.Is(err, service.ErrStorageUnavailable) {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(core.ErrorResponse{
|
||||
Error: "authentication storage unavailable", Code: core.ErrStorageUnavailable,
|
||||
})
|
||||
}
|
||||
|
||||
c.Locals("userID", userID)
|
||||
if sessionID, ok := claims["session_id"].(string); ok {
|
||||
c.Locals("sessionID", sessionID)
|
||||
}
|
||||
return c.Next()
|
||||
return invalidToken(c)
|
||||
}
|
||||
|
||||
c.Locals("userID", userID)
|
||||
if sessionID, ok := claims["session_id"].(string); ok {
|
||||
c.Locals("sessionID", sessionID)
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// extractBearerToken extracts JWT token from Authorization header
|
||||
func extractBearerToken(header string) string {
|
||||
const prefix = "Bearer "
|
||||
if !strings.HasPrefix(header, prefix) {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimPrefix(header, prefix)
|
||||
func invalidToken(c *fiber.Ctx) error {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(core.ErrorResponse{
|
||||
Error: "invalid or expired token", Code: core.ErrUnauthorized,
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user