Passed
Push — main ( 3ec306...c5cfaa )
by Yume
01:53 queued 44s
created

app/http/controllers/middleware.go   A

Size/Duplication

Total Lines 92
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 48
dl 0
loc 92
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A controllers.*JwtController.VerifyPermissions 0 2 1
C controllers.*JwtController.IsConnectedMiddleware 0 54 9
A controllers.NewJwtController 0 2 1
1
package controllers
2
3
import (
4
	"errors"
5
	"strconv"
6
7
	"github.com/getsentry/sentry-go"
8
	"github.com/gofiber/fiber/v2"
9
	"github.com/memnix/memnix-rest/config"
10
	"github.com/memnix/memnix-rest/domain"
11
	"github.com/memnix/memnix-rest/infrastructures"
12
	"github.com/memnix/memnix-rest/internal/user"
13
	"github.com/memnix/memnix-rest/views"
14
	"github.com/uptrace/opentelemetry-go-extra/otelzap"
15
	"go.uber.org/zap"
16
)
17
18
// JwtController is the controller for the jwt routes
19
type JwtController struct {
20
	user.IUseCase
21
}
22
23
// NewJwtController creates a new jwt controller
24
func NewJwtController(user user.IUseCase) JwtController {
25
	return JwtController{IUseCase: user}
26
}
27
28
// VerifyPermissions checks if the user has the required permissions
29
func (*JwtController) VerifyPermissions(user domain.User, p domain.Permission) bool {
30
	return user.HasPermission(p)
31
}
32
33
// IsConnectedMiddleware checks if the user is connected and has the required permissions
34
// the permissions are defined in the route definition
35
// returns an error if the user is not connected or has not the required permissions
36
//
37
// if the user is connected and has the required permissions, it sets the user in the locals
38
// and calls the next middleware
39
func (j *JwtController) IsConnectedMiddleware(p domain.Permission) func(c *fiber.Ctx) error {
40
	return func(c *fiber.Ctx) error {
41
		// check if the permission is valid
42
		if !p.IsValid() {
43
			return c.Status(fiber.StatusInternalServerError).JSON(views.NewHTTPResponseVMFromError(errors.New("invalid permission")))
44
		}
45
46
		// if the route is public, we don't need to check if the userModel is connected
47
		if p == domain.PermissionNone {
48
			return c.Next()
49
		}
50
51
		_, span := infrastructures.GetFiberTracer().Start(c.UserContext(), "IsConnectedMiddleware")
52
		defer span.End()
53
54
		// get the token from the request header
55
		tokenHeader := c.Get("Authorization")
56
		// if the token is empty, the userModel is not connected, and we return an error
57
		if tokenHeader == "" {
58
			return c.Status(fiber.StatusUnauthorized).JSON(views.NewHTTPResponseVMFromError(errors.New("unauthorized: token missing")))
59
		}
60
61
		// get the userModel from the token
62
		// if the token is invalid, we return an error
63
		userID, err := config.GetJwtInstance().GetConnectedUserID(c.UserContext(), tokenHeader)
64
		if err != nil {
65
			return c.Status(fiber.StatusUnauthorized).JSON(views.NewHTTPResponseVMFromError(errors.New("unauthorized: invalid token")))
66
		}
67
68
		// get the userModel from the database
69
		userModel, err := j.IUseCase.GetByID(c.UserContext(), userID)
70
		if err != nil {
71
			otelzap.Ctx(c.UserContext()).Error("error getting user / not connected", zap.Error(err))
72
			return c.Status(fiber.StatusUnauthorized).JSON(views.NewHTTPResponseVMFromError(errors.New("unauthorized: invalid user")))
73
		}
74
75
		sentry.ConfigureScope(func(scope *sentry.Scope) {
76
			scope.SetUser(sentry.User{
77
				ID:       strconv.Itoa(int(userModel.ID)),
78
				Username: userModel.Username,
79
				Email:    userModel.Email,
80
			})
81
		})
82
83
		// Check permissions
84
		if !j.VerifyPermissions(userModel, p) {
85
			otelzap.Ctx(c.UserContext()).Warn("Not authorized", zap.Error(errors.New("unauthorized: insufficient permissions")))
86
			return c.Status(fiber.StatusUnauthorized).JSON(views.NewHTTPResponseVMFromError(errors.New("unauthorized: insufficient permissions")))
87
		}
88
89
		// Set userModel in locals
90
		SetUserToContext(c, userModel)
91
		span.End()
92
		return c.Next()
93
	}
94
}
95