1+ from datetime import datetime , timedelta
12import os
23from flask import Flask , render_template , request , redirect , url_for , session , flash , jsonify
34import requests
1718
1819Logger ()
1920
21+ failed_login_attempts = dict () # Dictionary to track failed login attempts by username
22+ timeouts = dict () # Dictionary to track timeouts by client IP
2023
2124@app .route ('/' )
2225def home ():
@@ -29,17 +32,49 @@ def home():
2932
3033@app .route ('/login' , methods = ['GET' , 'POST' ])
3134def login ():
35+
36+ # check if the client is timed out
37+ client_ip = request .remote_addr
38+ if client_ip in timeouts :
39+ timeout = timeouts [client_ip ]
40+ if datetime .now () < timeout :
41+ flash ("Too many failed login attempts. Please try again later." , "error" )
42+ return render_template ('lockout.html' )
43+ else :
44+ del timeouts [client_ip ]
45+
3246 if request .method == 'POST' :
3347 username = request .form ['username' ]
3448 password = request .form ['password' ]
3549
3650 auth_res = authenticate_basic (username , password )
3751 if auth_res and auth_res .get_success ():
52+ # Reset failed login attempts for this client IP
53+ if client_ip in failed_login_attempts :
54+ del failed_login_attempts [client_ip ]
55+
3856 # session.permanent = False # <- this line ensures session ends on browser close
3957 session ['username' ] = username
4058 session ['token' ] = auth_res .get_payload ()[0 ]
4159 return redirect (url_for ('main_menu' ))
4260 else :
61+ if client_ip not in failed_login_attempts :
62+ failed_login_attempts [client_ip ] = 0
63+
64+ # Increment failed login attempts for this client IP
65+ failed_login_attempts [client_ip ] += 1
66+
67+ # increase the timeout based on the number of failed attempts
68+ if failed_login_attempts [client_ip ] >= 10 :
69+ Logger .log_info (f"Locking out client { client_ip } for 30 minutes due to too many failed login attempts." )
70+ timeouts [client_ip ] = datetime .now () + timedelta (minutes = 30 )
71+ elif failed_login_attempts [client_ip ] >= 5 :
72+ Logger .log_info (f"Locking out client { client_ip } for 10 minutes due to too many failed login attempts." )
73+ timeouts [client_ip ] = datetime .now () + timedelta (minutes = 10 )
74+ elif failed_login_attempts [client_ip ] >= 3 :
75+ Logger .log_info (f"Locking out client { client_ip } for 5 minutes due to too many failed login attempts." )
76+ timeouts [client_ip ] = datetime .now () + timedelta (minutes = 5 )
77+
4378 flash ("Invalid credentials" , "error" )
4479
4580 return render_template ('login.html' )
0 commit comments