@@ -17,7 +17,10 @@ import (
17
17
)
18
18
19
19
const (
20
+ attemptLimit = 5 * time .Minute
21
+ attemptBurst = 5
20
22
defCost = 12
23
+ apiTokenLength = 64
21
24
sessionKeyLength = 128
22
25
sessionExpireDefault = 2 * time .Hour
23
26
sessionExpireRemember = 30 * 24 * time .Hour
@@ -26,8 +29,10 @@ const (
26
29
var (
27
30
errBadRequest = errors .New ("bad request" )
28
31
errUnauthorized = errors .New ("unauthorized" )
32
+ errRateLimited = errors .New ("rate limited" )
29
33
30
- setCookieHeader = []byte ("Set-Cookie" )
34
+ setCookieHeader = []byte ("Set-Cookie" )
35
+ authorizationHeader = []byte ("Authorization" )
31
36
)
32
37
33
38
type loginRequest struct {
@@ -37,12 +42,14 @@ type loginRequest struct {
37
42
}
38
43
39
44
type Authorization struct {
40
- db database.Middleware
45
+ db database.Middleware
46
+ rlm * RateLimitManager
41
47
}
42
48
43
- func NewAuthorization (db database.Middleware ) (auth * Authorization ) {
49
+ func NewAuthorization (db database.Middleware , rlm * RateLimitManager ) (auth * Authorization ) {
44
50
auth = new (Authorization )
45
51
auth .db = db
52
+ auth .rlm = rlm
46
53
return
47
54
}
48
55
@@ -64,15 +71,23 @@ func (auth *Authorization) Login(ctx *routing.Context) bool {
64
71
return jsonError (ctx , errBadRequest , fasthttp .StatusBadRequest ) != nil
65
72
}
66
73
74
+ limiter := auth .rlm .GetLimiter (fmt .Sprintf ("loginAttempt#%s" , getIPAddr (ctx )), attemptLimit , attemptBurst )
75
+
76
+ if limiter .Tokens () <= 0 {
77
+ return jsonError (ctx , errRateLimited , fasthttp .StatusTooManyRequests ) != nil
78
+ }
79
+
67
80
user , err := auth .db .GetUser (snowflake .ID (- 1 ), strings .ToLower (login .UserName ))
68
81
if err != nil {
69
82
return jsonError (ctx , err , fasthttp .StatusInternalServerError ) != nil
70
83
}
71
84
if user == nil {
85
+ limiter .Allow ()
72
86
return jsonError (ctx , errUnauthorized , fasthttp .StatusUnauthorized ) != nil
73
87
}
74
88
75
89
if ! auth .CheckHash (user .PassHash , []byte (login .Password )) {
90
+ limiter .Allow ()
76
91
return jsonError (ctx , errUnauthorized , fasthttp .StatusUnauthorized ) != nil
77
92
}
78
93
@@ -110,12 +125,31 @@ func (auth *Authorization) CreateSession(ctx *routing.Context, uid snowflake.ID,
110
125
}
111
126
112
127
func (auth * Authorization ) CheckRequestAuth (ctx * routing.Context ) error {
113
- key := ctx .Request .Header .Cookie ("__session" )
114
- if key == nil || len (key ) == 0 {
115
- return jsonError (ctx , errUnauthorized , fasthttp .StatusUnauthorized )
128
+ var user * objects.User
129
+ var err error
130
+ var keyStr string
131
+ var apiToken string
132
+
133
+ apiTokenB := ctx .Request .Header .PeekBytes (authorizationHeader )
134
+ if apiTokenB != nil && len (apiTokenB ) > 0 {
135
+ apiToken := string (apiTokenB )
136
+ if ! strings .HasPrefix (strings .ToLower (apiToken ), "basic " ) {
137
+ return jsonError (ctx , errUnauthorized , fasthttp .StatusUnauthorized )
138
+ }
139
+
140
+ apiToken = apiToken [6 :]
141
+ user , err = auth .db .VerifyAPIToken (apiToken )
142
+ } else {
143
+ key := ctx .Request .Header .Cookie ("__session" )
144
+ if key == nil || len (key ) == 0 {
145
+ return jsonError (ctx , errUnauthorized , fasthttp .StatusUnauthorized )
146
+ }
147
+
148
+ keyStr = string (key )
149
+
150
+ user , err = auth .db .GetSession (keyStr , getIPAddr (ctx ))
116
151
}
117
152
118
- user , err := auth .db .GetSession (string (key ), getIPAddr (ctx ))
119
153
if err != nil {
120
154
return jsonError (ctx , err , fasthttp .StatusInternalServerError )
121
155
}
@@ -124,6 +158,8 @@ func (auth *Authorization) CheckRequestAuth(ctx *routing.Context) error {
124
158
}
125
159
126
160
ctx .Set ("user" , user )
161
+ ctx .Set ("sessionkey" , keyStr )
162
+ ctx .Set ("apitoken" , apiToken )
127
163
128
164
return nil
129
165
}
0 commit comments