From a725393fa701fda20051782b3a071cc3ca057e30 Mon Sep 17 00:00:00 2001 From: Casu Al Snek Date: Sat, 11 Jan 2025 15:38:01 +0545 Subject: [PATCH 1/5] Add role guard --- backend/utils/auth.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/backend/utils/auth.py b/backend/utils/auth.py index 24db859..f28b5f9 100644 --- a/backend/utils/auth.py +++ b/backend/utils/auth.py @@ -1,9 +1,14 @@ from functools import wraps from flask import request, jsonify -from sqlalchemy import select +from sqlalchemy import select, and_ from ..db.model import User, Session, db +from ..constants import UserRole +from typing import Union -def requires_role(roles=[]): +def requires_role(roles: Union[None, UserRole] = None): + if roles is None: + roles = [UserRole.USER] + roles = [int(r) for r in roles] def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): @@ -14,26 +19,19 @@ def requires_role(roles=[]): session_key = auth_header.split(' ')[1] except IndexError: return jsonify({'error': 'Invalid authorization header format'}), 401 - - session = db.session.execute( - - ) + session: Session = db.session.execute( + select(User).where(and_(Session.key == session_key, Session.isValid == True)) + ).scalar() if not session: return jsonify({'error': 'Invalid or expired session'}), 401 - user = User.query.get(session.userID) + user = session.user if not user: - return jsonify({'error': 'User not found'}), 401 - + return jsonify({'error': 'User not found for the Access token'}), 401 # If no roles specified, allow access if not roles: return f(*args, **kwargs) - - # Check if user has any of the required roles if user.role in roles: return f(*args, **kwargs) - - return jsonify({'error': 'Insufficient permissions'}), 403 - + return jsonify({'error': 'Not authorized'}), 403 return decorated_function - return decorator \ No newline at end of file From 9bf49396745df13e23f0e063c692f8a1ba918605 Mon Sep 17 00:00:00 2001 From: PANDACUSHION Date: Sat, 11 Jan 2025 15:39:05 +0545 Subject: [PATCH 2/5] made mail validation --- backend/utils/utils.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/utils/utils.py b/backend/utils/utils.py index f0fbc82..2098c68 100644 --- a/backend/utils/utils.py +++ b/backend/utils/utils.py @@ -3,6 +3,7 @@ import hashlib import random import os from PyPDF2 import PdfReader +import re FILE_NAME = 'manjil.pdf' FILE_PATH = os.path.join(os.getcwd(), FILE_NAME) @@ -24,4 +25,9 @@ def read_pdf_human_readable(file_path: str) -> list[str]: pdf_page_text_contents.append(text.strip()) return pdf_page_text_contents - +def is_valid_email(email): + pattern = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$' + if re.match(pattern, email): + return True + else: + return False \ No newline at end of file From ef9d32cda5fb6504c97ac6f33600b3e42363ac0d Mon Sep 17 00:00:00 2001 From: PANDACUSHION Date: Sat, 11 Jan 2025 16:10:44 +0545 Subject: [PATCH 3/5] password validation and exception --- backend/utils/utils.py | 52 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/backend/utils/utils.py b/backend/utils/utils.py index 2098c68..eeac0c5 100644 --- a/backend/utils/utils.py +++ b/backend/utils/utils.py @@ -30,4 +30,54 @@ def is_valid_email(email): if re.match(pattern, email): return True else: - return False \ No newline at end of file + return False + +def password_check(passwd: str) -> bool: + special_symbol_pattern = r'[$@#%]' + upper_case_pattern = r'[A-Z]' + lower_case_pattern = r'[a-z]' + digit_pattern = r'[0-9]' + + if len(passwd) < 6: + raise PasswordLengthMinException('Password length should be at least 6 characters.') + elif len(passwd) > 20: + raise PasswordLengthMaxException('Password length should not be greater than 20 characters.') + + if not re.search(digit_pattern, passwd): + raise PasswordNumericException('Password should have at least one numeral.') + + if not re.search(upper_case_pattern, passwd): + raise PasswordUppercaseException('Password should have at least one uppercase letter.') + + if not re.search(lower_case_pattern, passwd): + raise PasswordLowercaseException('Password should have at least one lowercase letter.') + + if not re.search(special_symbol_pattern, passwd): + raise PasswordSpecialSymbolException('Password should have at least one of the symbols $@#%.') + + return True + + +class PasswordLengthMinException(Exception): + def __init__(self, message): + self.message = message + +class PasswordLengthMaxException(Exception): + def __init__(self, message): + self.message = message + +class PasswordNumericException(Exception): + def __init__(self, message): + self.message = message + +class PasswordUppercaseException(Exception): + def __init__(self, message): + self.message = message + +class PasswordLowercaseException(Exception): + def __init__(self, message): + self.message = message + +class PasswordSpecialSymbolException(Exception): + def __init__(self, message): + self.message = message From c733a550ec4f8b197d92f2ad3a759141146d7799 Mon Sep 17 00:00:00 2001 From: PANDACUSHION Date: Sat, 11 Jan 2025 16:15:48 +0545 Subject: [PATCH 4/5] changed exception classes --- backend/utils/utils.py | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/backend/utils/utils.py b/backend/utils/utils.py index eeac0c5..3b23166 100644 --- a/backend/utils/utils.py +++ b/backend/utils/utils.py @@ -39,45 +39,24 @@ def password_check(passwd: str) -> bool: digit_pattern = r'[0-9]' if len(passwd) < 6: - raise PasswordLengthMinException('Password length should be at least 6 characters.') + raise InsecurePasswordException('Password length should be at least 6 characters.') elif len(passwd) > 20: - raise PasswordLengthMaxException('Password length should not be greater than 20 characters.') + raise InsecurePasswordException('Password length should not be greater than 20 characters.') if not re.search(digit_pattern, passwd): - raise PasswordNumericException('Password should have at least one numeral.') + raise InsecurePasswordException('Password should have at least one numeral.') if not re.search(upper_case_pattern, passwd): - raise PasswordUppercaseException('Password should have at least one uppercase letter.') + raise InsecurePasswordException('Password should have at least one uppercase letter.') if not re.search(lower_case_pattern, passwd): - raise PasswordLowercaseException('Password should have at least one lowercase letter.') + raise InsecurePasswordException('Password should have at least one lowercase letter.') if not re.search(special_symbol_pattern, passwd): - raise PasswordSpecialSymbolException('Password should have at least one of the symbols $@#%.') + raise InsecurePasswordException('Password should have at least one of the symbols $@#%.') return True -class PasswordLengthMinException(Exception): - def __init__(self, message): - self.message = message - -class PasswordLengthMaxException(Exception): - def __init__(self, message): - self.message = message - -class PasswordNumericException(Exception): - def __init__(self, message): - self.message = message - -class PasswordUppercaseException(Exception): - def __init__(self, message): - self.message = message - -class PasswordLowercaseException(Exception): - def __init__(self, message): - self.message = message - -class PasswordSpecialSymbolException(Exception): - def __init__(self, message): - self.message = message +class InsecurePasswordException(Exception): + pass From 8fee958f683dc323658b1c8e1948fe3e8ac6a3b5 Mon Sep 17 00:00:00 2001 From: PANDACUSHION Date: Sat, 11 Jan 2025 16:18:09 +0545 Subject: [PATCH 5/5] Allow disabling sanity checks --- backend/config.py | 1 + backend/utils/utils.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/backend/config.py b/backend/config.py index 50abd11..27514ab 100644 --- a/backend/config.py +++ b/backend/config.py @@ -15,6 +15,7 @@ DB_NAME: str = "educonnect" DEFAULT_PROFILE_FILE: str = "defaultUserBanner.png" DEFAULT_COURSE_COVER: str = "defaultCourseCover.png" DEFAULT_BADGE_ICON: str = "defaultBadgeIcon.png" +DISABLE_PASSWORD_SANITY_CHECKS: bool = True PROJECT_ROOT: os.path = os.path.dirname(os.path.abspath(__file__)) USER_UPLOADS_DIR: str = os.path.join(PROJECT_ROOT, "uploads") diff --git a/backend/utils/utils.py b/backend/utils/utils.py index 3b23166..70b23ad 100644 --- a/backend/utils/utils.py +++ b/backend/utils/utils.py @@ -3,6 +3,7 @@ import hashlib import random import os from PyPDF2 import PdfReader +from config import * import re FILE_NAME = 'manjil.pdf' @@ -33,6 +34,8 @@ def is_valid_email(email): return False def password_check(passwd: str) -> bool: + if DISABLE_PASSWORD_SANITY_CHECKS: + return True special_symbol_pattern = r'[$@#%]' upper_case_pattern = r'[A-Z]' lower_case_pattern = r'[a-z]'