From bf5d1d2d4500dd66ec339e152f8651ae36773f06 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:59:30 +0000 Subject: [PATCH 1/2] fix(auth): prevent info leakage in login_required error response Co-authored-by: Pmaster-dev <293764797+Pmaster-dev@users.noreply.github.com> --- auth/utils.py | 13 ++++++--- tests/test_auth.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 tests/test_auth.py diff --git a/auth/utils.py b/auth/utils.py index 4bded89..6a2ea13 100644 --- a/auth/utils.py +++ b/auth/utils.py @@ -1,14 +1,18 @@ -import bcrypt -import jwt +import logging import os import secrets from datetime import datetime, timedelta from functools import wraps +from typing import Tuple, Optional + +import bcrypt +import jwt from flask import request, jsonify, g from flask_jwt_extended import get_jwt_identity, verify_jwt_in_request from cache_db.redis_client import redis_client from cache_db.models import User, RefreshToken -from typing import Tuple, Optional + +logger = logging.getLogger(__name__) class PasswordUtils: @@ -129,7 +133,8 @@ def decorated_function(*args, **kwargs): g.user = user_data return f(*args, **kwargs) except Exception as e: - return jsonify({'error': 'Unauthorized', 'details': str(e)}), 401 + logger.exception("Unauthorized access attempt: %s", e) + return jsonify({'error': 'Unauthorized'}), 401 return decorated_function diff --git a/tests/test_auth.py b/tests/test_auth.py new file mode 100644 index 0000000..acaae91 --- /dev/null +++ b/tests/test_auth.py @@ -0,0 +1,69 @@ +""" +Unit tests for auth/utils.py security fixes and utilities. +""" + +import sys +from unittest.mock import MagicMock + +# Mock external cache_db module before importing auth.utils +cache_db_mock = MagicMock() +sys.modules['cache_db'] = cache_db_mock +sys.modules['cache_db.redis_client'] = cache_db_mock.redis_client +sys.modules['cache_db.models'] = cache_db_mock.models + +import pytest +from flask import Flask, jsonify +from auth.utils import PasswordUtils, JWTUtils, login_required + + +@pytest.fixture +def app(): + """Create a test Flask application.""" + app = Flask(__name__) + app.config['SECRET_KEY'] = 'test-secret-key' + app.config['JWT_SECRET_KEY'] = 'test-jwt-secret-key' + + @app.route('/protected') + @login_required + def protected(): + return jsonify({'message': 'success'}) + + return app + + +def test_password_hashing(): + """Test password hashing and verification.""" + password = "SuperSecretPassword123!" + hashed = PasswordUtils.hash_password(password) + assert hashed != password + assert PasswordUtils.verify_password(password, hashed) is True + assert PasswordUtils.verify_password("WrongPassword", hashed) is False + + +def test_password_length_validation(): + """Test password length requirement.""" + with pytest.raises(ValueError, match="at least 8 characters"): + PasswordUtils.hash_password("short") + + +def test_jwt_token_creation_and_decoding(): + """Test JWT token creation and decoding.""" + access_token, refresh_token = JWTUtils.create_tokens("user123", "testuser") + assert access_token is not None + assert refresh_token is not None + + decoded_access = JWTUtils.decode_token(access_token) + assert decoded_access is not None + assert decoded_access["user_id"] == "user123" + assert decoded_access["username"] == "testuser" + assert decoded_access["type"] == "access" + + +def test_login_required_unauthorized_no_leak(app): + """Test that login_required returns 401 and does NOT leak internal exception details.""" + with app.test_client() as client: + response = client.get('/protected') + assert response.status_code == 401 + data = response.get_json() + assert data == {'error': 'Unauthorized'} + assert 'details' not in data From df7d2c70d47163ee46eb74dabdfbddea70af3046 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:24:57 +0000 Subject: [PATCH 2/2] fix(auth): prevent info leakage in login_required error response Co-authored-by: Pmaster-dev <293764797+Pmaster-dev@users.noreply.github.com>