294 lines
9.3 KiB
Go
294 lines
9.3 KiB
Go
package httpserver
|
|
|
|
import (
|
|
"Yimaru-Backend/internal/domain"
|
|
jwtutil "Yimaru-Backend/internal/web_server/jwt"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func (a *App) authMiddleware(c *fiber.Ctx) error {
|
|
ip := c.IP()
|
|
userAgent := c.Get("User-Agent")
|
|
c.Locals("ip_address", ip)
|
|
c.Locals("user_agent", userAgent)
|
|
authHeader := c.Get("Authorization")
|
|
if authHeader == "" {
|
|
a.mongoLoggerSvc.Info("Authorization header missing",
|
|
zap.Int("status_code", fiber.StatusUnauthorized),
|
|
zap.String("ip_address", ip),
|
|
zap.String("user_agent", userAgent),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Authorization header missing")
|
|
}
|
|
|
|
if !strings.HasPrefix(authHeader, "Bearer ") {
|
|
a.mongoLoggerSvc.Info("Invalid authorization header format",
|
|
zap.String("authHeader", authHeader),
|
|
zap.Int("status_code", fiber.StatusUnauthorized),
|
|
zap.String("ip_address", ip),
|
|
zap.String("user_agent", userAgent),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid authorization header format")
|
|
}
|
|
|
|
accessToken := strings.TrimPrefix(authHeader, "Bearer ")
|
|
c.Locals("access_token", accessToken)
|
|
claim, err := jwtutil.ParseJwt(accessToken, a.JwtConfig.JwtAccessKey)
|
|
if err != nil {
|
|
if errors.Is(err, jwtutil.ErrExpiredToken) {
|
|
a.mongoLoggerSvc.Info("Access Token Expired",
|
|
zap.Int("status_code", fiber.StatusUnauthorized),
|
|
zap.String("ip_address", ip),
|
|
zap.String("user_agent", userAgent),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Access token expired")
|
|
}
|
|
a.mongoLoggerSvc.Info("Invalid Access Token",
|
|
zap.Int("status_code", fiber.StatusUnauthorized),
|
|
zap.String("ip_address", ip),
|
|
zap.String("user_agent", userAgent),
|
|
zap.Time("timestamp", time.Now()),
|
|
zap.Error(err),
|
|
)
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token")
|
|
}
|
|
|
|
refreshToken := c.Get("Refresh-Token")
|
|
if refreshToken == "" {
|
|
|
|
// refreshToken = c.Cookies("refresh_token", "")
|
|
// return fiber.NewError(fiber.StatusUnauthorized, "Refresh token missing")
|
|
|
|
}
|
|
// Asserting to make sure that only the super admin can have a nil company ID
|
|
// if claim.Role != domain.RoleSuperAdmin && !claim.CompanyID.Valid {
|
|
// a.mongoLoggerSvc.Error("Company Role without Company ID",
|
|
// zap.Int64("userID", claim.UserId),
|
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
|
// zap.Error(err),
|
|
// zap.Time("timestamp", time.Now()),
|
|
// )
|
|
// return fiber.NewError(fiber.StatusInternalServerError, "Company Role without Company ID")
|
|
// }
|
|
c.Locals("user_id", claim.UserId)
|
|
c.Locals("role", claim.Role)
|
|
// c.Locals("company_id", domain.ValidInt64{
|
|
// Value: claim.CompanyID.Value,
|
|
// Valid: claim.CompanyID.Valid,
|
|
// })
|
|
c.Locals("refresh_token", refreshToken)
|
|
|
|
// var branchID domain.ValidInt64
|
|
|
|
if claim.Role == domain.RoleAdmin {
|
|
// branch, err := a.branchSvc.GetBranchByCashier(c.Context(), claim.UserId)
|
|
// if err != nil {
|
|
// a.mongoLoggerSvc.Error("Failed to get branch id for cashier",
|
|
// zap.Int64("userID", claim.UserId),
|
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
|
// zap.Error(err),
|
|
// zap.Time("timestamp", time.Now()),
|
|
// )
|
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to branch id for cashier")
|
|
// }
|
|
// branchID = domain.ValidInt64{
|
|
// Value: branch.ID,
|
|
// Valid: true,
|
|
// }
|
|
|
|
}
|
|
|
|
// c.Locals("branch_id", branchID)
|
|
return c.Next()
|
|
}
|
|
|
|
func (a *App) SuperAdminOnly(c *fiber.Ctx) error {
|
|
userID := c.Locals("user_id").(int64)
|
|
userRole := c.Locals("role").(domain.Role)
|
|
if userRole != domain.RoleSuperAdmin {
|
|
a.mongoLoggerSvc.Warn("Attempt to access restricted SuperAdminOnly route",
|
|
zap.Int64("userID", userID),
|
|
zap.String("role", string(userRole)),
|
|
zap.Int("status_code", fiber.StatusForbidden),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusForbidden, "This route is restricted")
|
|
}
|
|
return c.Next()
|
|
}
|
|
|
|
// func (a *App) CompanyOnly(c *fiber.Ctx) error {
|
|
// userID := c.Locals("user_id").(int64)
|
|
// userRole := c.Locals("role").(domain.Role)
|
|
// if userRole == domain.RoleStudent {
|
|
// a.mongoLoggerSvc.Warn("Attempt to access restricted CompanyOnly route",
|
|
// zap.Int64("userID", userID),
|
|
// zap.String("role", string(userRole)),
|
|
// zap.Int("status_code", fiber.StatusForbidden),
|
|
// zap.Time("timestamp", time.Now()),
|
|
// )
|
|
// return fiber.NewError(fiber.StatusForbidden, "This route is restricted")
|
|
// }
|
|
// return c.Next()
|
|
// }
|
|
|
|
func (a *App) OnlyAdminAndAbove(c *fiber.Ctx) error {
|
|
userID := c.Locals("user_id").(int64)
|
|
userRole := c.Locals("role").(domain.Role)
|
|
if userRole != domain.RoleSuperAdmin && userRole != domain.RoleAdmin {
|
|
a.mongoLoggerSvc.Warn("Attempt to access restricted OnlyAdminAndAbove route",
|
|
zap.Int64("userID", userID),
|
|
zap.String("role", string(userRole)),
|
|
zap.Int("status_code", fiber.StatusForbidden),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusForbidden, "This route is restricted")
|
|
}
|
|
return c.Next()
|
|
}
|
|
|
|
func (a *App) OnlyBranchManagerAndAbove(c *fiber.Ctx) error {
|
|
userID := c.Locals("user_id").(int64)
|
|
userRole := c.Locals("role").(domain.Role)
|
|
if userRole != domain.RoleSuperAdmin && userRole != domain.RoleAdmin {
|
|
a.mongoLoggerSvc.Warn("Attempt to access restricted OnlyBranchMangerAndAbove route",
|
|
zap.Int64("userID", userID),
|
|
zap.String("role", string(userRole)),
|
|
zap.Int("status_code", fiber.StatusForbidden),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusForbidden, "This route is restricted")
|
|
}
|
|
return c.Next()
|
|
}
|
|
|
|
func (a *App) WebsocketAuthMiddleware(c *fiber.Ctx) error {
|
|
tokenStr := c.Query("token")
|
|
ip := c.IP()
|
|
userAgent := c.Get("User-Agent")
|
|
|
|
if tokenStr == "" {
|
|
a.mongoLoggerSvc.Info("Missing token in query parameter",
|
|
zap.Int("status_code", fiber.StatusUnauthorized),
|
|
zap.String("ip_address", ip),
|
|
zap.String("user_agent", userAgent),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Missing token")
|
|
}
|
|
|
|
claim, err := jwtutil.ParseJwt(tokenStr, a.JwtConfig.JwtAccessKey)
|
|
if err != nil {
|
|
if errors.Is(err, jwtutil.ErrExpiredToken) {
|
|
a.mongoLoggerSvc.Info("Token expired",
|
|
zap.Int("status_code", fiber.StatusUnauthorized),
|
|
zap.String("ip_address", ip),
|
|
zap.String("user_agent", userAgent),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Token expired")
|
|
}
|
|
a.logger.Error("Invalid token", "error", err)
|
|
a.mongoLoggerSvc.Info("Invalid token",
|
|
zap.Int("status_code", fiber.StatusUnauthorized),
|
|
zap.String("ip_address", ip),
|
|
zap.String("user_agent", userAgent),
|
|
zap.Time("timestamp", time.Now()),
|
|
zap.Error(err),
|
|
)
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid token")
|
|
}
|
|
|
|
userID := claim.UserId
|
|
if userID == 0 {
|
|
a.mongoLoggerSvc.Info("Invalid user ID in token claims",
|
|
zap.Int("status_code", fiber.StatusUnauthorized),
|
|
zap.String("ip_address", ip),
|
|
zap.String("user_agent", userAgent),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid user ID")
|
|
}
|
|
|
|
c.Locals("userID", userID)
|
|
a.mongoLoggerSvc.Info("Authenticated WebSocket connection",
|
|
zap.Int64("userID", userID),
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return c.Next()
|
|
}
|
|
|
|
func (a *App) TenantMiddleware(c *fiber.Ctx) error {
|
|
tenantSlug := c.Params("tenant_slug")
|
|
if tenantSlug == "" {
|
|
a.mongoLoggerSvc.Info("blank tenant param",
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusBadRequest, "tenant is required for this route")
|
|
}
|
|
|
|
// company, err := a.companySvc.GetCompanyBySlug(c.Context(), tenantSlug)
|
|
// if err != nil {
|
|
// a.mongoLoggerSvc.Info("failed to resolve tenant",
|
|
// zap.String("tenant_slug", tenantSlug),
|
|
// zap.Time("timestamp", time.Now()),
|
|
// )
|
|
// return fiber.NewError(fiber.StatusBadRequest, "failed to resolve tenant")
|
|
// }
|
|
|
|
// if !company.IsActive {
|
|
// a.mongoLoggerSvc.Info("request using deactivated tenant",
|
|
// zap.String("tenant_slug", tenantSlug),
|
|
// zap.Time("timestamp", time.Now()),
|
|
// )
|
|
// return fiber.NewError(fiber.StatusForbidden, "this tenant has been deactivated")
|
|
// }
|
|
|
|
// c.Locals("company_id", domain.ValidInt64{
|
|
// Value: company.ID,
|
|
// Valid: true,
|
|
// })
|
|
return c.Next()
|
|
}
|
|
|
|
func (a *App) TenantAuthMiddleware(c *fiber.Ctx) error {
|
|
slugID, ok := c.Locals("tenant_id").(domain.ValidInt64)
|
|
|
|
if !ok || !slugID.Valid {
|
|
a.mongoLoggerSvc.Info("invalid tenant slug",
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid tenant slug")
|
|
}
|
|
|
|
tokenCID, ok := c.Locals("company_id").(domain.ValidInt64)
|
|
if !ok || !tokenCID.Valid {
|
|
a.mongoLoggerSvc.Error("invalid company id in token",
|
|
zap.Time("timestamp", time.Now()),
|
|
zap.Bool("tokenCID Valid", tokenCID.Valid),
|
|
zap.Bool("ValidInt64 Type Check", ok),
|
|
)
|
|
return fiber.NewError(fiber.StatusInternalServerError, "invalid company id in token")
|
|
}
|
|
|
|
if slugID.Value != tokenCID.Value {
|
|
a.mongoLoggerSvc.Error("token company-id doesn't match the slug company_id",
|
|
zap.Time("timestamp", time.Now()),
|
|
)
|
|
return fiber.NewError(fiber.StatusInternalServerError, "invalid company_id")
|
|
}
|
|
|
|
fmt.Printf("\nTenant successfully authenticated!\n")
|
|
|
|
return c.Next()
|
|
}
|