Fix .gitignore and add missing authentication source files

This commit fixes overly broad .gitignore patterns that were excluding
important source code files from version control. Previously, wildcard
patterns like *auth*, *token*, *secret*, *connection*, and *credential*
were excluding ALL files containing these words, including critical
application code.

Changes:
- Updated .gitignore with specific patterns for sensitive config files
  (*.json, *.txt, *.yml, *.yaml extensions only)
- Removed broad wildcards that excluded source code files

Added missing source files:
- shared/auth/ (9 files): Complete authentication system
  - JWT handler, middleware, auth service, models, routes
- reports-app/backend/app/routers/auth.py: Authentication API router
- reports-app/backend/app/auth_middleware_wrapper.py: Middleware wrapper
- reports-app/frontend/src/stores/auth.js: Vue.js auth store
- reports-app/frontend/tests/: E2E tests and fixtures for auth
- reports-app/telegram-bot/app/auth/: Telegram auth linking module
- deployment/windows/scripts/Setup-ClaudeAuth.ps1: Windows deployment script
- security/secrets_scanner.py: Security scanning utility

These files are essential for the application to function and should
have been included in the initial commit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-25 15:02:28 +03:00
parent 6b13ffa183
commit f42eff71a6
19 changed files with 5035 additions and 21 deletions

View File

@@ -0,0 +1,78 @@
"""
Wrapper pentru AuthenticationMiddleware cu fix pentru endpoint-urile protejate
"""
from fastapi import Request, status
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '../../../shared'))
from auth.middleware import AuthenticationMiddleware
from auth.models import AuthError
class FixedAuthenticationMiddleware(BaseHTTPMiddleware):
"""
Wrapper pentru AuthenticationMiddleware care aplică fix-ul pentru endpoint-urile protejate
"""
def __init__(self, app, **kwargs):
super().__init__(app)
# Create the original middleware instance without wrapping in BaseHTTPMiddleware
self.auth_middleware = AuthenticationMiddleware(app, **kwargs)
print("[FIXED MIDDLEWARE] FixedAuthenticationMiddleware initialized")
print(f"[FIXED MIDDLEWARE] Original middleware type: {type(self.auth_middleware)}")
async def dispatch(self, request: Request, call_next):
"""
Aplică fix-ul pentru endpoint-urile protejate:
- Returnează 401 pentru căile protejate fără token în loc să seteze request.state
"""
path = request.url.path
print(f"[FIXED MIDDLEWARE] Processing path: {path}")
# Verifică dacă path-ul trebuie exclus
excluded_paths = ["/docs", "/health", "/api/auth/login", "/redoc", "/openapi.json"]
is_excluded = (path == "/" or any(path.startswith(excluded) for excluded in excluded_paths))
print(f"[FIXED MIDDLEWARE] Checking exclusions for {path}")
print(f"[FIXED MIDDLEWARE] Excluded paths: {excluded_paths}")
print(f"[FIXED MIDDLEWARE] Is excluded: {is_excluded}")
if is_excluded:
print(f"[FIXED MIDDLEWARE] Path {path} is excluded, skipping auth")
request.state.user = None
request.state.is_authenticated = False
response = await call_next(request)
return response
# Extrage token-ul
authorization = request.headers.get("Authorization")
print(f"[FIXED MIDDLEWARE] Authorization header: {authorization}")
if not authorization or not authorization.startswith("Bearer "):
print(f"[FIXED MIDDLEWARE] No valid token for protected path {path}, returning 401")
error = AuthError(
error="authentication_required",
error_description="Authentication required",
error_code="AUTH_003"
)
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content=error.dict(),
headers={"WWW-Authenticate": "Bearer"}
)
# Token există, să îl validez prin middleware-ul original
print(f"[FIXED MIDDLEWARE] Token found, delegating to original middleware")
try:
result = await self.auth_middleware.dispatch(request, call_next)
print(f"[FIXED MIDDLEWARE] Original middleware returned: {type(result)}")
print(f"[FIXED MIDDLEWARE] Request state after middleware: user={getattr(request.state, 'user', 'MISSING')}, is_authenticated={getattr(request.state, 'is_authenticated', 'MISSING')}")
return result
except Exception as e:
print(f"[FIXED MIDDLEWARE] Exception in original middleware: {str(e)}")
raise

View File

@@ -0,0 +1,109 @@
"""
API Router pentru autentificare - Wrapper peste shared auth
"""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import HTTPBearer
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '../../../../shared'))
from auth.dependencies import get_current_user
from auth.models import LoginRequest, TokenResponse, CurrentUser
from auth.auth_service import auth_service
from pydantic import BaseModel
router = APIRouter()
security = HTTPBearer()
class LogoutResponse(BaseModel):
"""Răspuns pentru logout"""
message: str
success: bool
@router.post("/login", response_model=TokenResponse)
async def login(login_request: LoginRequest):
"""
Autentificare utilizator cu username și parola
Folosește shared auth service pentru validarea credențialelor
și generarea token-urilor JWT
"""
try:
# Folosește shared auth service pentru autentificare
success, token_response, error_message = await auth_service.authenticate_and_create_tokens(
username=login_request.username,
password=login_request.password
)
if not success:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=error_message or "Authentication failed",
headers={"WWW-Authenticate": "Bearer"},
)
return token_response
except HTTPException:
raise # Re-raise HTTP exceptions as-is
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Internal authentication error"
)
@router.post("/logout", response_model=LogoutResponse)
async def logout(current_user: CurrentUser = Depends(get_current_user)):
"""
Logout utilizator
Pentru moment doar confirmă logout-ul (token-urile JWT nu sunt invalidate server-side)
În viitor poate fi extins cu blacklist de token-uri
"""
try:
return LogoutResponse(
message=f"Utilizatorul {current_user.username} a fost deconectat cu succes",
success=True
)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Eroare la logout: {str(e)}"
)
@router.get("/me", response_model=CurrentUser)
async def get_current_user_info(current_user: CurrentUser = Depends(get_current_user)):
"""
Obține informațiile utilizatorului curent
Returnează datele utilizatorului din token-ul JWT
"""
return current_user
@router.post("/refresh")
async def refresh_token(refresh_token: str):
"""
Reîmprospătează token-ul de acces folosind refresh token-ul
Această funcție va fi implementată în viitor pentru gestionarea
completă a ciclului de viață al token-urilor
"""
raise HTTPException(
status_code=status.HTTP_501_NOT_IMPLEMENTED,
detail="Refresh token nu este încă implementat"
)
@router.get("/validate")
async def validate_token(current_user: CurrentUser = Depends(get_current_user)):
"""
Validează token-ul curent
Endpoint util pentru frontend să verifice dacă token-ul este încă valid
"""
return {
"valid": True,
"user": current_user.username,
"companies": current_user.companies,
"message": "Token valid"
}