all repos

onasty @ ff7bfce

a one-time notes service

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

Smirnov Oleksandr Smirnov Oleksandr
ss2316544@gmail.com
feat: impl the core of the app, notes (#5)..., 1 year ago
1
package apiv1
2
3
import (
4
	"context"
5
	"errors"
6
	"strings"
7
8
	"github.com/gin-gonic/gin"
9
	"github.com/gofrs/uuid/v5"
10
	"github.com/olexsmir/onasty/internal/service/usersrv"
11
)
12
13
var ErrUnauthorized = errors.New("unauthorized")
14
15
const userIDCtxKey = "userID"
16
17
func (a *APIV1) authorizedMiddleware(c *gin.Context) {
18
	token, ok := getTokenFromAuthHeaders(c)
19
	if !ok {
20
		errorResponse(c, ErrUnauthorized)
21
		return
22
	}
23
24
	ok, err := checkIfUserIsReal(c.Request.Context(), token, a.usersrv)
25
	if err != nil {
26
		errorResponse(c, err)
27
		return
28
	}
29
30
	if !ok {
31
		errorResponse(c, ErrUnauthorized)
32
		return
33
	}
34
35
	if err := saveUserIDToCtx(c, a.usersrv, token); err != nil {
36
		errorResponse(c, err)
37
		return
38
	}
39
40
	c.Next()
41
}
42
43
func (a *APIV1) couldBeAuthorizedMiddleware(c *gin.Context) {
44
	token, ok := getTokenFromAuthHeaders(c)
45
	if ok {
46
		ok, err := checkIfUserIsReal(c.Request.Context(), token, a.usersrv)
47
		if err != nil {
48
			errorResponse(c, err)
49
			return
50
		}
51
52
		if !ok {
53
			errorResponse(c, ErrUnauthorized)
54
			return
55
		}
56
57
		if err := saveUserIDToCtx(c, a.usersrv, token); err != nil {
58
			newInternalError(c, err)
59
			return
60
		}
61
	}
62
63
	c.Next()
64
}
65
66
//nolint:unused // TODO: remove me later
67
func (a *APIV1) isUserAuthorized(c *gin.Context) bool {
68
	return !a.getUserID(c).IsNil()
69
}
70
71
func getTokenFromAuthHeaders(c *gin.Context) (token string, ok bool) { //nolint:nonamedreturns
72
	header := c.GetHeader("Authorization")
73
	if header == "" {
74
		return "", false
75
	}
76
77
	headerParts := strings.Split(header, " ")
78
	if len(headerParts) != 2 && headerParts[0] != "Bearer" {
79
		return "", false
80
	}
81
82
	if len(headerParts[1]) == 0 {
83
		return "", false
84
	}
85
86
	return headerParts[1], true
87
}
88
89
func saveUserIDToCtx(c *gin.Context, us usersrv.UserServicer, token string) error {
90
	pl, err := us.ParseToken(token)
91
	if err != nil {
92
		return err
93
	}
94
95
	c.Set(userIDCtxKey, pl.UserID)
96
97
	return nil
98
}
99
100
// getUserId returns userId from the context
101
// getting user id is only possible if user is authorized
102
func (a *APIV1) getUserID(c *gin.Context) uuid.UUID {
103
	userID, exists := c.Get(userIDCtxKey)
104
	if !exists {
105
		return uuid.Nil
106
	}
107
	return uuid.Must(uuid.FromString(userID.(string)))
108
}
109
110
func checkIfUserIsReal(
111
	ctx context.Context,
112
	accessToken string,
113
	us usersrv.UserServicer,
114
) (bool, error) {
115
	parsedToken, err := us.ParseToken(accessToken)
116
	if err != nil {
117
		return false, err
118
	}
119
120
	return us.CheckIfUserExists(
121
		ctx,
122
		uuid.Must(uuid.FromString(parsedToken.UserID)),
123
	)
124
}