diff --git a/.gitignore b/.gitignore index 59bf362..594a3b6 100644 --- a/.gitignore +++ b/.gitignore @@ -174,6 +174,6 @@ poetry.toml pyrightconfig.json # Database file -.db +*.db # End of https://www.toptal.com/developers/gitignore/api/python diff --git a/app/__init__.py b/app/__init__.py index 8a622c3..4e492d7 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,18 +1,24 @@ """ author: @GUU8HC """ -#pylint: disable=import-outside-toplevel +#pylint: disable=import-outside-toplevel, line-too-long from flask import Flask -from app.settings import DEBUG_MODE, USER_DB, SECRET_KEY, SESSION_COOKIE_HTTPONLY, SESSION_COOKIE_SECURE, SESSION_PERMANENT +from app.settings import DEBUG_MODE, USER_DB, SECRET_KEY, SESSION_COOKIE_HTTPONLY, SESSION_COOKIE_SECURE, SESSION_PERMANENT, SESSION_COOKIE_SAMESITE def create_app(): """ function to create application + Issues: + #2.c: Session Security """ app = Flask(__name__) app.config['SECRET_KEY'] = SECRET_KEY + app.config['SESSION_COOKIE_SECURE'] = SESSION_COOKIE_SECURE + app.config['SESSION_COOKIE_HTTPONLY'] = SESSION_COOKIE_HTTPONLY + app.config['SESSION_COOKIE_SAMESITE'] = SESSION_COOKIE_SAMESITE + app.config['SESSION_PERMANENT'] = SESSION_PERMANENT from app.home import home_bp app.register_blueprint(home_bp, url_prefix='/home') diff --git a/app/authentication/authentication.py b/app/authentication/authentication.py index a3c9059..ad57c57 100644 --- a/app/authentication/authentication.py +++ b/app/authentication/authentication.py @@ -7,6 +7,7 @@ from app.authenticator import authenticator from app.util import login_user, logout_user from app.util import get_git_branch +from app.settings import DEBUG_MODE from . import authentication_bp @@ -30,7 +31,12 @@ def authenticate(username, password): route: /auth/signin// """ login_user(username) - return jsonify({'result': authenticator.authenticate(username, password)}) + result = authenticator.authenticate(username, password) + + if DEBUG_MODE: + print(f"[DEBUG] authentication.py: Authentication result: {result}") + + return jsonify({'result': result}) @authentication_bp.route('/registration') def registration(): diff --git a/app/authentication/static/signin.js b/app/authentication/static/signin.js index 28acc16..3529bb7 100644 --- a/app/authentication/static/signin.js +++ b/app/authentication/static/signin.js @@ -1,11 +1,14 @@ -document.getElementById('button-signin').addEventListener('click', function(event) { - event.preventDefault(); // Prevent form submission - const username = document.querySelector('input[type="text"]').value; - const password = document.querySelector('input[type="password"]').value; - authenticate(username, password) +document.addEventListener("DOMContentLoaded", function() { + document.getElementById('button-signin').addEventListener('click', function(event) { + event.preventDefault(); // Prevent form submission + const username = document.querySelector('input[type="text"]').value; + const password = document.querySelector('input[type="password"]').value; + authenticate(username, password) + }); }); function authenticate(username, password) { + console.log("[DEBUG] signin.js: authenticate() called"); fetch(`/auth/signin/${username}/${password}`, { method: 'GET', headers: { diff --git a/app/authenticator/authenticator.py b/app/authenticator/authenticator.py index 3b08ff5..0362a80 100644 --- a/app/authenticator/authenticator.py +++ b/app/authenticator/authenticator.py @@ -4,9 +4,10 @@ #pylint: disable=wrong-import-position #pylint: disable=line-too-long -import hashlib +from bcrypt import checkpw, gensalt, hashpw from app.database.user import User +from app.settings import DEBUG_MODE class Authenticator: """ @@ -20,6 +21,29 @@ def __init__(self, db: User): """ self.db = db + def hash_password(self, password): + """ + Hashes a given password using bcrypt. + Args: + password (str): The plaintext password to be hashed. + Returns: + str: The hashed password as a UTF-8 encoded string. + """ + return hashpw(password.encode(), gensalt()).decode('utf-8') + + def verify_password(self, password, hashed_password): + """ + Verifies if the provided password matches the hashed password. + Args: + password (str): The plain text password to verify. + hashed_password (str): The hashed password to compare against. + Returns: + bool: True if the password matches the hashed password, False otherwise. + """ + if DEBUG_MODE: + print(f"[DEBUG] authenticator.py: Verifying password: {checkpw(password.encode(), hashed_password.encode())}") + return checkpw(password.encode(), hashed_password.encode()) + def authenticate(self, username, password): """ Authenticate user. @@ -34,19 +58,7 @@ def authenticate(self, username, password): user = self.db.get_user_by_username(username) # Perform password validation if user exists - return user[-1] == self.hash_password(password) if user else False - - def hash_password(self, password): - """ - Return the SHA-256 hash of a password. - - Args: - password (String): The provided password. - - Returns: - String: The SHA-256 hash of the password. - """ - return hashlib.sha256(password.encode()).hexdigest() + return self.verify_password(password, user[-1]) if user else False def register(self, username, password): """ diff --git a/app/database/dbs/user.db b/app/database/dbs/user.db index 073a2e3..e02e8ac 100644 Binary files a/app/database/dbs/user.db and b/app/database/dbs/user.db differ diff --git a/app/home/static/home-private.js b/app/home/static/home-private.js index a676dc4..f2f2f52 100644 --- a/app/home/static/home-private.js +++ b/app/home/static/home-private.js @@ -1,6 +1,8 @@ -document.getElementById('button-signout').addEventListener('click', function(event) { +document.addEventListener("DOMContentLoaded", function() { + document.getElementById('button-signout').addEventListener('click', function(event) { event.preventDefault(); redirect_signout(); + }); }); function redirect_signout(){ diff --git a/app/settings.py b/app/settings.py index 80a9d30..a124d8f 100644 --- a/app/settings.py +++ b/app/settings.py @@ -12,3 +12,4 @@ SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SECURE = True # Use this in production with HTTPS SESSION_PERMANENT = False +SESSION_COOKIE_SAMESITE = 'Strict' # CSRF protection