-
Notifications
You must be signed in to change notification settings - Fork 0
/
sessions.go
180 lines (133 loc) · 4.43 KB
/
sessions.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package auth
import (
"context"
"fmt"
"net/http"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/zmzlois/LinkGoGo/pkg/model"
"github.com/zmzlois/LinkGoGo/pkg/utils"
)
var CookieName = fmt.Sprintf("_LinkGoGo-session-token-%s", ScopeIdentify)
type Claims struct {
UserID int `json:"user_id"`
Username string `json:"username"`
GlobalName string `json:"global_name"`
Avatar string `json:"avatar"`
State string `json:"state"`
RefreshToken string `json:"refresh_token"`
AccessToken string `json:"access_token"`
Exp float64 `json:"exp"`
jwt.RegisteredClaims
}
func (dc *Client) CreateToken(userData *model.LoginUserInput, tokenInput *model.TokenInput, state string) (tokenString string, err error) {
jwtMapClaim := jwt.MapClaims{
"user_id": userData.Id,
"username": userData.Username,
"avatar": userData.Avatar,
"global_name": userData.GlobalName,
"state": state,
"refresh_token": tokenInput.RefreshToken,
"access_token": tokenInput.AccessToken,
"exp": time.Now().Add(168 * time.Hour).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtMapClaim)
tokenString, err = token.SignedString([]byte(utils.Config("JWT_SECRET_KEY")))
if err != nil {
fmt.Printf("[Create JWT Token]: %s", err)
return "", err
}
return tokenString, nil
}
func (dc *Client) SetCookie(tokenString string, w http.ResponseWriter) {
cookie := http.Cookie{
Name: CookieName,
Value: tokenString,
Expires: time.Now().Add(168 * time.Hour),
Secure: false,
HttpOnly: true,
// SameSite: http.SameSiteStrictMode,
MaxAge: 168 * 60 * 60,
}
http.SetCookie(w, &cookie)
}
func ValidateToken(tokenString string) (bool, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(utils.Config("JWT_SECRET_KEY")), nil
})
if err != nil || !token.Valid {
return false, err
}
return true, nil
}
func GetToken(r *http.Request) (string, error) {
tokenFromCookie, err := r.Cookie(CookieName)
if err != nil {
return "", fmt.Errorf("discordClient.GetToken: %w failed to get token, loging user out", err)
}
return tokenFromCookie.Value, nil
}
func RetrieveTokenValue(field string, r *http.Request) (jwt.MapClaims, interface{}, error) {
claims := jwt.MapClaims{}
tokenFromCookie, err := r.Cookie(CookieName)
if err != nil {
return claims, "", fmt.Errorf("discordClient.RetrieveTokenValue: %w", err)
}
tokenString := tokenFromCookie.Value
// Parse the JWT token string
// FIXME: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// Return the key used for signing the token (you need this to validate the token)
// Here, you would typically return the same key that was used for signing the token
return []byte(utils.Config("JWT_SECRET_KEY")), nil
})
// Check for errors during parsing
if err != nil {
fmt.Println("discordClient.RetrieveTokenValue.Error parsing JWT token:", err)
return claims, "", fmt.Errorf("discordClient.RetrieveTokenValue: %w", err)
}
// Check if the token is valid
if !token.Valid {
fmt.Println("Invalid JWT token")
return claims, "", fmt.Errorf("discordClient.RetrieveTokenValue: %w", err)
}
// Retrieve claims from the token
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
fmt.Println("Invalid token claims format")
return claims, "", fmt.Errorf("discordClient.RetrieveTokenValue: %w", err)
}
// Access specific claims
result := claims[field]
// username := claims["username"].(string)
return claims, result, nil
}
func WithSession(ctx context.Context, key interface{}, ctxValue string) context.Context {
return context.WithValue(ctx, key, ctxValue)
}
func GetSessionValue(ctx context.Context, key interface{}) string {
value, ok := ctx.Value(key).(string)
if !ok {
return ""
}
return value
}
func CleanUpContext(ctx context.Context) context.Context {
// Create a new context derived from the existing one, without the unwanted values
newCtx := context.Background()
return newCtx
}
func IsUser(r *http.Request) (bool, error) {
token, err := GetToken(r)
if err != nil {
return false, err
}
result, err := ValidateToken(token)
if err != nil {
return false, err
}
return result, nil
}