1
+ from datetime import timedelta
1
2
from logging import getLogger
2
3
from time import sleep
3
4
23
24
CustomUserRegistrationSerializer ,
24
25
ResetPasswordSerializer ,
25
26
)
27
+ from .utils import is_rate_limited
26
28
27
29
logger = getLogger (__name__ )
28
30
@@ -44,8 +46,10 @@ def get_queryset(self, *args, **kwargs):
44
46
def check_permissions (self , request ):
45
47
super ().check_permissions (request )
46
48
# If it's a 'list' action and user is not admin, deny access
47
- if self .action == 'list' and not request .user .is_staff :
48
- raise PermissionDenied ("You do not have permission to view the list of users." )
49
+ if self .action == "list" and not request .user .is_staff :
50
+ raise PermissionDenied (
51
+ "You do not have permission to view the list of users."
52
+ )
49
53
50
54
51
55
class AuthView (APIView ):
@@ -75,6 +79,15 @@ def post(self, request):
75
79
76
80
class RegisterView (APIView ):
77
81
def post (self , request ):
82
+ # Check if the rate limit has been exceeded
83
+ if is_rate_limited (
84
+ request .META ['REMOTE_ADDR' ], "init_registration" , max_attempts = 20 , period = timedelta (hours = 1 )
85
+ ):
86
+ return Response (
87
+ {"detail" : "Registration requests are limited to 20 per hour." },
88
+ status = status .HTTP_429_TOO_MANY_REQUESTS ,
89
+ )
90
+
78
91
logger .info (f"Registering user with email: { request .data ['email' ]} " )
79
92
serializer = CustomUserRegistrationSerializer (data = request .data )
80
93
@@ -156,6 +169,15 @@ def post(self, request):
156
169
157
170
class ConfirmRegistrationView (APIView ):
158
171
def get (self , request , uidb64 , token ):
172
+ # Check if the rate limit has been exceeded
173
+ if is_rate_limited (
174
+ request .META ['REMOTE_ADDR' ], "confirm_registration" , max_attempts = 50 , period = timedelta (hours = 1 )
175
+ ):
176
+ return Response (
177
+ {"detail" : "Please stop spamming the confirmation endpoint." },
178
+ status = status .HTTP_429_TOO_MANY_REQUESTS ,
179
+ )
180
+
159
181
logger .info (f"Confirming registration for user with uidb64: { uidb64 } " )
160
182
try :
161
183
uid = force_str (urlsafe_base64_decode (uidb64 ))
@@ -179,6 +201,15 @@ def get(self, request, uidb64, token):
179
201
180
202
class ForgotPasswordView (APIView ):
181
203
def post (self , request ):
204
+ # Check if the rate limit has been exceeded
205
+ if is_rate_limited (
206
+ request .META ['REMOTE_ADDR' ], "forgot_password" , max_attempts = 5 , period = timedelta (hours = 1 )
207
+ ):
208
+ return Response (
209
+ {"detail" : "Password reset requests are limited to 5 per hour." },
210
+ status = status .HTTP_429_TOO_MANY_REQUESTS ,
211
+ )
212
+
182
213
logger .info (
183
214
f"Forgot password request for user with email: { request .data ['email' ]} "
184
215
)
@@ -245,6 +276,15 @@ def post(self, request):
245
276
246
277
class CompleteForgotPasswordView (APIView ):
247
278
def post (self , request , uidb64 , token ):
279
+ # Check if the rate limit has been exceeded
280
+ if is_rate_limited (
281
+ request .META ['REMOTE_ADDR' ], "new_password" , max_attempts = 20 , period = timedelta (hours = 1 )
282
+ ):
283
+ return Response (
284
+ {"detail" : "Please stop spamming the password reset endpoint." },
285
+ status = status .HTTP_429_TOO_MANY_REQUESTS ,
286
+ )
287
+
248
288
logger .info (f"Completing forgot password for user with uidb64: { uidb64 } " )
249
289
try :
250
290
uid = force_str (urlsafe_base64_decode (uidb64 ))
0 commit comments