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 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 )
@@ -69,6 +76,8 @@ export class LoginHttpProvider extends HttpProvider {
69
76
70
77
/**
71
78
* Return a cookie if the user is authenticated otherwise throw an error.
79
+ *
80
+ * Only allows max 3 logins a second.
72
81
*/
73
82
private async login ( payload : LoginPayload , route : Route , request : http . IncomingMessage ) : Promise < HttpResponse > {
74
83
const password = this . authenticated ( request , {
@@ -108,3 +117,18 @@ export class LoginHttpProvider extends HttpProvider {
108
117
throw new Error ( "Missing password" )
109
118
}
110
119
}
120
+
121
+ // RateLimiter wraps around the limiter library for logins.
122
+ // It allows 2 logins every minute and 12 logins every hour.
123
+ class RateLimiter {
124
+ private readonly minuteLimiter = new limiter . RateLimiter ( 2 , "minute" )
125
+ private readonly hourLimiter = new limiter . RateLimiter ( 12 , "hour" )
126
+
127
+ public try ( ) : boolean {
128
+ console . info ( this . minuteLimiter . getTokensRemaining ( ) , this . hourLimiter . getTokensRemaining ( ) )
129
+ if ( this . minuteLimiter . tryRemoveTokens ( 1 ) ) {
130
+ return true
131
+ }
132
+ return this . hourLimiter . tryRemoveTokens ( 1 )
133
+ }
134
+ }
0 commit comments