Initial commit: Robot ökoszisztéma v2.0 - Stabilizált jármű és szerviz robotok
This commit is contained in:
94
backend/app/services/security_service.py
Executable file
94
backend/app/services/security_service.py
Executable file
@@ -0,0 +1,94 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/services/security_service.py
|
||||
import logging
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Optional, Any, Dict
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, func, and_
|
||||
from app.models.security import PendingAction, ActionStatus
|
||||
from app.models.history import AuditLog, LogSeverity
|
||||
from app.models.identity import User
|
||||
from app.models.system import SystemParameter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class SecurityService:
|
||||
@staticmethod
|
||||
async def get_sec_config(db: AsyncSession) -> Dict[str, Any]:
|
||||
""" Lekéri a korlátokat a központi system_parameters-ből. """
|
||||
stmt = select(SystemParameter).where(SystemParameter.key.in_(["SECURITY_MAX_RECORDS_PER_HOUR", "SECURITY_DUAL_CONTROL_ENABLED"]))
|
||||
res = await db.execute(stmt)
|
||||
params = {p.key: p.value for p in res.scalars().all()}
|
||||
|
||||
return {
|
||||
"max_records": int(params.get("SECURITY_MAX_RECORDS_PER_HOUR", 500)),
|
||||
"dual_control": str(params.get("SECURITY_DUAL_CONTROL_ENABLED", "true")).lower() == "true"
|
||||
}
|
||||
|
||||
async def log_event(self, db: AsyncSession, user_id: Optional[int], action: str, severity: LogSeverity, **kwargs):
|
||||
""" LOGIKA MEGŐRIZVE: Audit naplózás + Emergency Lock trigger. """
|
||||
new_log = AuditLog(
|
||||
user_id=user_id, severity=severity, action=action,
|
||||
target_type=kwargs.get("target_type"), target_id=kwargs.get("target_id"),
|
||||
old_data=kwargs.get("old_data"), new_data=kwargs.get("new_data"),
|
||||
ip_address=kwargs.get("ip"), user_agent=kwargs.get("ua")
|
||||
)
|
||||
db.add(new_log)
|
||||
|
||||
if severity == LogSeverity.emergency:
|
||||
await self._execute_emergency_lock(db, user_id, f"Auto-lock by: {action}")
|
||||
|
||||
await db.commit()
|
||||
|
||||
async def request_action(self, db: AsyncSession, requester_id: int, action_type: str, payload: Dict, reason: str):
|
||||
""" NÉGY SZEM ELV: Jóváhagyási kérelem indítása. """
|
||||
new_action = PendingAction(
|
||||
requester_id=requester_id, action_type=action_type,
|
||||
payload=payload, reason=reason, status=ActionStatus.pending
|
||||
)
|
||||
db.add(new_action)
|
||||
await db.commit()
|
||||
return new_action
|
||||
|
||||
async def approve_action(self, db: AsyncSession, approver_id: int, action_id: int):
|
||||
""" Jóváhagyás végrehajtása (Logic Preserved: Ön-jóváhagyás tiltva). """
|
||||
stmt = select(PendingAction).where(PendingAction.id == action_id)
|
||||
action = (await db.execute(stmt)).scalar_one_or_none()
|
||||
|
||||
if not action or action.status != ActionStatus.pending:
|
||||
raise Exception("Művelet nem található.")
|
||||
if action.requester_id == approver_id:
|
||||
raise Exception("Saját kérést nem hagyhatsz jóvá!")
|
||||
|
||||
# Üzleti logika (pl. Role változtatás)
|
||||
if action.action_type == "CHANGE_ROLE":
|
||||
target_user = (await db.execute(select(User).where(User.id == action.payload.get("user_id")))).scalar_one_or_none()
|
||||
if target_user: target_user.role = action.payload.get("new_role")
|
||||
|
||||
action.status = ActionStatus.approved
|
||||
action.approver_id = approver_id
|
||||
action.processed_at = datetime.now(timezone.utc)
|
||||
await db.commit()
|
||||
|
||||
async def check_data_access_limit(self, db: AsyncSession, user_id: int):
|
||||
""" DATA THROTTLING: Adatlopás elleni védelem. """
|
||||
config = await self.get_sec_config(db)
|
||||
limit_time = datetime.now(timezone.utc) - timedelta(hours=1)
|
||||
|
||||
stmt = select(func.count(AuditLog.id)).where(
|
||||
and_(AuditLog.user_id == user_id, AuditLog.timestamp >= limit_time, AuditLog.action.like("GET_%"))
|
||||
)
|
||||
count = (await db.execute(stmt)).scalar() or 0
|
||||
|
||||
if count > config["max_records"]:
|
||||
await self.log_event(db, user_id, "MASS_DATA_ACCESS", LogSeverity.emergency, reason=f"Count: {count}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def _execute_emergency_lock(self, db: AsyncSession, user_id: int, reason: str):
|
||||
if not user_id: return
|
||||
user = (await db.execute(select(User).where(User.id == user_id))).scalar_one_or_none()
|
||||
if user:
|
||||
user.is_active = False
|
||||
logger.critical(f"🚨 EMERGENCY LOCK: User {user_id} suspended. Reason: {reason}")
|
||||
|
||||
security_service = SecurityService()
|
||||
Reference in New Issue
Block a user