1
1
import * as http from "http"
2
+ import * as limiter from "limiter"
2
3
import * as querystring from "querystring"
3
4
import { HttpCode , HttpError } from "../../common/http"
4
5
import { AuthType , HttpProvider , HttpResponse , Route } from "../http"
@@ -48,6 +49,8 @@ export class LoginHttpProvider extends HttpProvider {
48
49
return this . replaceTemplates ( route , response )
49
50
}
50
51
52
+ private readonly limiter = new RateLimiter ( )
53
+
51
54
/**
52
55
* Try logging in. On failure, show the login page with an error.
53
56
*/
@@ -59,6 +62,10 @@ export class LoginHttpProvider extends HttpProvider {
59
62
}
60
63
61
64
try {
65
+ if ( ! this . limiter . try ( ) ) {
66
+ throw new Error ( "Login rate limited!" )
67
+ }
68
+
62
69
const data = await this . getData ( request )
63
70
const payload = data ? querystring . parse ( data ) : { }
64
71
return await this . login ( payload , route , request )
@@ -108,3 +115,17 @@ export class LoginHttpProvider extends HttpProvider {
108
115
throw new Error ( "Missing password" )
109
116
}
110
117
}
118
+
119
+ // RateLimiter wraps around the limiter library for logins.
120
+ // It allows 2 logins every minute and 12 logins every hour.
121
+ class RateLimiter {
122
+ private readonly minuteLimiter = new limiter . RateLimiter ( 2 , "minute" )
123
+ private readonly hourLimiter = new limiter . RateLimiter ( 12 , "hour" )
124
+
125
+ public try ( ) : boolean {
126
+ if ( this . minuteLimiter . tryRemoveTokens ( 1 ) ) {
127
+ return true
128
+ }
129
+ return this . hourLimiter . tryRemoveTokens ( 1 )
130
+ }
131
+ }
0 commit comments