all repos

onasty @ 07561ca

a one-time notes service

onasty/internal/transport/http/apiv1/middleware.go (view raw)

Smirnov Oleksandr Smirnov Oleksandr
ss2316544@gmail.com
feat: send emails on sign-up (#6)..., 1 year ago
1
package apiv1
2
3
import (
4
	"context"
5
	"strings"
6
7
	"github.com/gin-gonic/gin"
8
	"github.com/gofrs/uuid/v5"
9
	"github.com/olexsmir/onasty/internal/models"
10
)
11
12
const userIDCtxKey = "userID"
13
14
// authorizedMiddleware is a middleware that checks if user is authorized
15
// and if so sets user metadata to context
16
//
17
// being authorized is required for making the request for specific endpoint
18
func (a *APIV1) authorizedMiddleware(c *gin.Context) {
19
	token, ok := getTokenFromAuthHeaders(c)
20
	if !ok {
21
		errorResponse(c, ErrUnauthorized)
22
		return
23
	}
24
25
	uid, err := a.validateAuthorizedUser(c.Request.Context(), token)
26
	if err != nil {
27
		errorResponse(c, err)
28
		return
29
	}
30
31
	c.Set(userIDCtxKey, uid)
32
33
	c.Next()
34
}
35
36
// couldBeAuthorizedMiddleware is a middleware that checks if user is authorized and
37
// if so sets user metadata to context
38
//
39
// it is NOT required to be authorized for making the request for specific endpoint
40
func (a *APIV1) couldBeAuthorizedMiddleware(c *gin.Context) {
41
	token, ok := getTokenFromAuthHeaders(c)
42
	if ok {
43
		uid, err := a.validateAuthorizedUser(c.Request.Context(), token)
44
		if err != nil {
45
			errorResponse(c, err)
46
			return
47
		}
48
49
		c.Set(userIDCtxKey, uid)
50
	}
51
52
	c.Next()
53
}
54
55
//nolint:unused // TODO: remove me later
56
func (a *APIV1) isUserAuthorized(c *gin.Context) bool {
57
	return !a.getUserID(c).IsNil()
58
}
59
60
func getTokenFromAuthHeaders(c *gin.Context) (token string, ok bool) { //nolint:nonamedreturns
61
	header := c.GetHeader("Authorization")
62
	if header == "" {
63
		return "", false
64
	}
65
66
	headerParts := strings.Split(header, " ")
67
	if len(headerParts) != 2 && headerParts[0] != "Bearer" {
68
		return "", false
69
	}
70
71
	if len(headerParts[1]) == 0 {
72
		return "", false
73
	}
74
75
	return headerParts[1], true
76
}
77
78
// getUserId returns userId from the context
79
// getting user id is only possible if user is authorized
80
func (a *APIV1) getUserID(c *gin.Context) uuid.UUID {
81
	userID, exists := c.Get(userIDCtxKey)
82
	if !exists {
83
		return uuid.Nil
84
	}
85
	return userID.(uuid.UUID)
86
}
87
88
func (a *APIV1) validateAuthorizedUser(ctx context.Context, accessToken string) (uuid.UUID, error) {
89
	tokenPayload, err := a.usersrv.ParseJWTToken(accessToken)
90
	if err != nil {
91
		return uuid.Nil, err
92
	}
93
94
	userID := uuid.Must(uuid.FromString(tokenPayload.UserID))
95
96
	ok, err := a.usersrv.CheckIfUserExists(ctx, userID)
97
	if err != nil {
98
		return uuid.Nil, err
99
	}
100
101
	if !ok {
102
		return uuid.Nil, ErrUnauthorized
103
	}
104
105
	ok, err = a.usersrv.CheckIfUserIsActivated(ctx, userID)
106
	if err != nil {
107
		return uuid.Nil, err
108
	}
109
110
	if !ok {
111
		return uuid.Nil, models.ErrUserIsNotActivated
112
	}
113
114
	return userID, nil
115
}