208 lines
5.4 KiB
Go
208 lines
5.4 KiB
Go
package middleware
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.ma-al.com/goc_daniel/b2b/app/config"
|
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
|
"git.ma-al.com/goc_daniel/b2b/app/service/authService"
|
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
|
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
)
|
|
|
|
// AuthMiddleware creates authentication middleware
|
|
func AuthMiddleware() fiber.Handler {
|
|
authService := authService.NewAuthService()
|
|
|
|
return func(c fiber.Ctx) error {
|
|
// Get token from Authorization header
|
|
authHeader := c.Get("Authorization")
|
|
if authHeader == "" {
|
|
// Try to get from cookie
|
|
authHeader = c.Cookies("access_token")
|
|
if authHeader == "" {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "authorization token required",
|
|
})
|
|
}
|
|
} else {
|
|
// Extract token from "Bearer <token>"
|
|
parts := strings.Split(authHeader, " ")
|
|
if len(parts) != 2 || parts[0] != "Bearer" {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "invalid authorization header format",
|
|
})
|
|
}
|
|
authHeader = parts[1]
|
|
}
|
|
|
|
// Validate token
|
|
claims, err := authService.ValidateToken(authHeader)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "invalid or expired token",
|
|
})
|
|
}
|
|
|
|
// Get user from database
|
|
user, err := authService.GetUserByID(claims.UserID)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "user not found",
|
|
})
|
|
}
|
|
|
|
// Check if user is active
|
|
if !user.IsActive {
|
|
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
|
"error": "user account is inactive",
|
|
})
|
|
}
|
|
|
|
// Create locale. LangID is overwritten by auth Token
|
|
var userLocale model.UserLocale
|
|
userLocale.OriginalUser = user
|
|
|
|
// Check if target user is present
|
|
targetUserIDAttribute := c.Query("target_user_id")
|
|
|
|
if targetUserIDAttribute == "" {
|
|
userLocale.User = user
|
|
c.Locals(constdata.USER_LOCALE, &userLocale)
|
|
|
|
return c.Next()
|
|
}
|
|
|
|
// We now populate the target user
|
|
if user.Role != model.RoleAdmin {
|
|
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
|
"error": "admin access required",
|
|
})
|
|
}
|
|
|
|
targetUserID, err := strconv.Atoi(targetUserIDAttribute)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "invalid target user id attribute",
|
|
})
|
|
}
|
|
|
|
// to verify target user, we use the same functionality as for verifying original user
|
|
// Get target user from database
|
|
user, err = authService.GetUserByID(uint(targetUserID))
|
|
if err != nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "target user not found",
|
|
})
|
|
}
|
|
|
|
// Check if target user is active
|
|
if !user.IsActive {
|
|
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
|
"error": "target user account is inactive",
|
|
})
|
|
}
|
|
|
|
userLocale.User = user
|
|
c.Locals(constdata.USER_LOCALE, &userLocale)
|
|
|
|
return c.Next()
|
|
}
|
|
}
|
|
|
|
// RequireAdmin creates admin-only middleware
|
|
func RequireAdmin() fiber.Handler {
|
|
return func(c fiber.Ctx) error {
|
|
originalUserRole, ok := localeExtractor.GetOriginalUserRole(c)
|
|
if !ok {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "not authenticated",
|
|
})
|
|
}
|
|
|
|
if originalUserRole != model.RoleAdmin {
|
|
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
|
"error": "admin access required",
|
|
})
|
|
}
|
|
|
|
return c.Next()
|
|
}
|
|
}
|
|
|
|
// Webdav
|
|
func Webdav() fiber.Handler {
|
|
authService := authService.NewAuthService()
|
|
|
|
return func(c fiber.Ctx) error {
|
|
authHeader := c.Get("Authorization")
|
|
if authHeader == "" {
|
|
c.Set("WWW-Authenticate", `Basic realm="webdav"`)
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "authorization token required",
|
|
})
|
|
}
|
|
|
|
if !strings.HasPrefix(authHeader, "Basic ") {
|
|
c.Set("WWW-Authenticate", `Basic realm="webdav"`)
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "invalid authorization token",
|
|
})
|
|
}
|
|
|
|
encoded := strings.TrimPrefix(authHeader, "Basic ")
|
|
decoded, err := base64.StdEncoding.DecodeString(encoded)
|
|
if err != nil {
|
|
c.Set("WWW-Authenticate", `Basic realm="webdav"`)
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "invalid authorization token",
|
|
})
|
|
}
|
|
|
|
credentials := strings.SplitN(string(decoded), ":", 2)
|
|
rawToken := ""
|
|
if len(credentials) == 1 {
|
|
rawToken = credentials[0]
|
|
} else if len(credentials) == 2 {
|
|
rawToken = credentials[1]
|
|
}
|
|
if len(rawToken) != constdata.NBYTES_IN_WEBDAV_TOKEN*2 {
|
|
c.Set("WWW-Authenticate", `Basic realm="webdav"`)
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "invalid authorization token",
|
|
})
|
|
}
|
|
|
|
// we identify user based on this token.
|
|
user, err := authService.GetUserByWebdavToken(rawToken)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "user not found",
|
|
})
|
|
}
|
|
|
|
if user.WebdavExpires != nil && user.WebdavExpires.Before(time.Now()) {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "invalid or expired token",
|
|
})
|
|
}
|
|
|
|
var userLocale model.UserLocale
|
|
userLocale.OriginalUser = user
|
|
userLocale.User = user
|
|
c.Locals(constdata.USER_LOCALE, &userLocale)
|
|
|
|
return c.Next()
|
|
}
|
|
}
|
|
|
|
// GetConfig returns the app config
|
|
func GetConfig() *config.Config {
|
|
return config.Get()
|
|
}
|