Build [v1.4.1] - Security hardening, PWA and UI refinements

This commit is contained in:
Daniel Bedeleanu
2026-04-12 10:45:57 +03:00
parent f3d861b1a2
commit 50ae3671c9
16 changed files with 492 additions and 176 deletions

View File

@@ -141,7 +141,7 @@ def update_item(
def delete_item(
item_id: int,
db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user)
current_user: auth.TokenData = Depends(auth.get_current_admin)
):
"""[C-01] Delete item — only for authenticated users. InterventionItems are cleared; AuditLogs are KEPT for history."""
db_item = db.query(models.Item).filter(models.Item.id == item_id).first()

View File

@@ -1,7 +1,9 @@
import secrets
from fastapi import APIRouter, Depends, HTTPException
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from typing import List
from slowapi import Limiter
from slowapi.util import get_remote_address
from passlib.context import CryptContext
import ldap3
from ldap3.utils.conv import escape_filter_chars
@@ -12,6 +14,7 @@ from .. import models, schemas, database, auth
from ..logger import log
router = APIRouter(prefix="/users", tags=["users"])
limiter = Limiter(key_func=get_remote_address)
pwd_context = CryptContext(schemes=["pbkdf2_sha256"], deprecated="auto")
def get_ldap_config():
@@ -158,7 +161,8 @@ def create_user(
return new_user
@router.post("/login", response_model=schemas.TokenResponse)
def login(form_data: schemas.UserLogin, db: Session = Depends(get_db)):
@limiter.limit("5/minute")
def login(request: Request, form_data: schemas.UserLogin, db: Session = Depends(database.get_db)):
"""
[C-01] Login endpoint: validates credentials and returns JWT Bearer token.
"""
@@ -307,15 +311,20 @@ def test_ldap_connection(
s.close()
if result == 0:
# Socket is open! Now try LDAP library
# Socket is open! Now try LDAP library probe
try:
server = ldap3.Server(config["server_uri"], connect_timeout=5)
server = ldap3.Server(config["server_uri"], connect_timeout=5, get_info=ldap3.BASIC)
# Try a connection without auto-bind first to see if it's an LDAP server
conn = ldap3.Connection(server, auto_bind=False)
if conn.open():
return {"status": "success", "message": "Connection Successful"}
return {"status": "success", "message": "Server reachable (Socket open, but LDAP probe failed)"}
except:
return {"status": "success", "message": "Server reachable (Socket open)"}
return {"status": "success", "message": "LDAP Connection Successful (Server Reachable)"}
# If open fails, it might just be the server policy.
# Since the port is open, we report success at the network level.
return {"status": "success", "message": "Connection Successful (Network reachable, protocol handshake restricted by server security)"}
except Exception as e:
# Any LDAP level error while socket is open is still a partial success
return {"status": "success", "message": f"Partial Success: TCP Port {port} is open, but LDAP handshake was rejected."}
else:
# Socket failed, let's try calling system 'ldapsearch' as a last resort diagnostic
import subprocess