diff --git a/backend/config.py b/backend/config.py index 692ecdc..18417ad 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/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 diff --git a/backend/utils/utils.py b/backend/utils/utils.py index f0fbc82..70b23ad 100644 --- a/backend/utils/utils.py +++ b/backend/utils/utils.py @@ -3,6 +3,8 @@ import hashlib import random import os from PyPDF2 import PdfReader +from config import * +import re FILE_NAME = 'manjil.pdf' FILE_PATH = os.path.join(os.getcwd(), FILE_NAME) @@ -24,4 +26,40 @@ 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 + +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]' + digit_pattern = r'[0-9]' + + if len(passwd) < 6: + raise InsecurePasswordException('Password length should be at least 6 characters.') + elif len(passwd) > 20: + raise InsecurePasswordException('Password length should not be greater than 20 characters.') + if not re.search(digit_pattern, passwd): + raise InsecurePasswordException('Password should have at least one numeral.') + + if not re.search(upper_case_pattern, passwd): + raise InsecurePasswordException('Password should have at least one uppercase letter.') + + if not re.search(lower_case_pattern, passwd): + raise InsecurePasswordException('Password should have at least one lowercase letter.') + + if not re.search(special_symbol_pattern, passwd): + raise InsecurePasswordException('Password should have at least one of the symbols $@#%.') + + return True + + +class InsecurePasswordException(Exception): + pass