zen-ai-pentest 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. agents/__init__.py +28 -0
  2. agents/agent_base.py +239 -0
  3. agents/agent_orchestrator.py +346 -0
  4. agents/analysis_agent.py +225 -0
  5. agents/cli.py +258 -0
  6. agents/exploit_agent.py +224 -0
  7. agents/integration.py +211 -0
  8. agents/post_scan_agent.py +937 -0
  9. agents/react_agent.py +384 -0
  10. agents/react_agent_enhanced.py +616 -0
  11. agents/react_agent_vm.py +298 -0
  12. agents/research_agent.py +176 -0
  13. api/__init__.py +11 -0
  14. api/auth.py +123 -0
  15. api/main.py +1027 -0
  16. api/schemas.py +357 -0
  17. api/websocket.py +97 -0
  18. autonomous/__init__.py +122 -0
  19. autonomous/agent.py +253 -0
  20. autonomous/agent_loop.py +1370 -0
  21. autonomous/exploit_validator.py +1537 -0
  22. autonomous/memory.py +448 -0
  23. autonomous/react.py +339 -0
  24. autonomous/tool_executor.py +488 -0
  25. backends/__init__.py +16 -0
  26. backends/chatgpt_direct.py +133 -0
  27. backends/claude_direct.py +130 -0
  28. backends/duckduckgo.py +138 -0
  29. backends/openrouter.py +120 -0
  30. benchmarks/__init__.py +149 -0
  31. benchmarks/benchmark_engine.py +904 -0
  32. benchmarks/ci_benchmark.py +785 -0
  33. benchmarks/comparison.py +729 -0
  34. benchmarks/metrics.py +553 -0
  35. benchmarks/run_benchmarks.py +809 -0
  36. ci_cd/__init__.py +2 -0
  37. core/__init__.py +17 -0
  38. core/async_pool.py +282 -0
  39. core/asyncio_fix.py +222 -0
  40. core/cache.py +472 -0
  41. core/container.py +277 -0
  42. core/database.py +114 -0
  43. core/input_validator.py +353 -0
  44. core/models.py +288 -0
  45. core/orchestrator.py +611 -0
  46. core/plugin_manager.py +571 -0
  47. core/rate_limiter.py +405 -0
  48. core/secure_config.py +328 -0
  49. core/shield_integration.py +296 -0
  50. modules/__init__.py +46 -0
  51. modules/cve_database.py +362 -0
  52. modules/exploit_assist.py +330 -0
  53. modules/nuclei_integration.py +480 -0
  54. modules/osint.py +604 -0
  55. modules/protonvpn.py +554 -0
  56. modules/recon.py +165 -0
  57. modules/sql_injection_db.py +826 -0
  58. modules/tool_orchestrator.py +498 -0
  59. modules/vuln_scanner.py +292 -0
  60. modules/wordlist_generator.py +566 -0
  61. risk_engine/__init__.py +99 -0
  62. risk_engine/business_impact.py +267 -0
  63. risk_engine/business_impact_calculator.py +563 -0
  64. risk_engine/cvss.py +156 -0
  65. risk_engine/epss.py +190 -0
  66. risk_engine/example_usage.py +294 -0
  67. risk_engine/false_positive_engine.py +1073 -0
  68. risk_engine/scorer.py +304 -0
  69. web_ui/backend/main.py +471 -0
  70. zen_ai_pentest-2.0.0.dist-info/METADATA +795 -0
  71. zen_ai_pentest-2.0.0.dist-info/RECORD +75 -0
  72. zen_ai_pentest-2.0.0.dist-info/WHEEL +5 -0
  73. zen_ai_pentest-2.0.0.dist-info/entry_points.txt +2 -0
  74. zen_ai_pentest-2.0.0.dist-info/licenses/LICENSE +21 -0
  75. zen_ai_pentest-2.0.0.dist-info/top_level.txt +10 -0
@@ -0,0 +1,298 @@
1
+ """
2
+ ReAct Agent mit VirtualBox VM-Integration
3
+
4
+ Erweiterung des ReAct Agents für isolierte VM-basierte Pentests.
5
+ """
6
+
7
+ from typing import List, TypedDict, Annotated, Literal
8
+ import logging
9
+
10
+ from langchain_core.tools import tool
11
+ from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, ToolMessage, SystemMessage
12
+ from langchain_core.prompts import ChatPromptTemplate
13
+ from langgraph.graph import StateGraph, START, END, add_messages
14
+ from langgraph.checkpoint.memory import MemorySaver
15
+
16
+ from .react_agent import ReActAgent, ReActAgentConfig, AgentState
17
+ from ..virtualization.vm_manager import VirtualBoxManager, PentestSandbox
18
+
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class VMAgentConfig(ReActAgentConfig):
24
+ """Erweiterte Konfiguration für VM-basierten Agent"""
25
+ use_vm: bool = True
26
+ vm_name: str = "kali-pentest"
27
+ vm_username: str = "kali"
28
+ vm_password: str = "kali"
29
+ auto_restore_snapshot: bool = True
30
+
31
+
32
+ class VMReActAgent(ReActAgent):
33
+ """
34
+ ReAct Agent mit VM-Backend.
35
+
36
+ Führt alle Tools in einer isolierten Kali Linux VM aus
37
+ für maximale Sicherheit und Reproduzierbarkeit.
38
+ """
39
+
40
+ def __init__(self, config: VMAgentConfig = None):
41
+ self.vm_config = config or VMAgentConfig()
42
+
43
+ # VM Manager initialisieren
44
+ if self.vm_config.use_vm:
45
+ self.vbox = VirtualBoxManager()
46
+ self.sandbox = PentestSandbox(self.vbox)
47
+ self.session_id = None
48
+
49
+ # Parent init ohne Tools (wir überschreiben sie)
50
+ self.config = self.vm_config
51
+ self.llm = None # Wird in _build_graph gesetzt
52
+ self.tools = []
53
+ self.graph = self._build_graph_with_vm()
54
+
55
+ logger.info(f"VMReActAgent initialisiert (VM: {self.vm_config.vm_name})")
56
+
57
+ def _build_graph_with_vm(self):
58
+ """Baut Graph mit VM-Tools"""
59
+ from ..core.llm_backend import LLMBackend
60
+
61
+ self.llm = LLMBackend(model=self.config.llm_model)
62
+
63
+ # VM-basierte Tools erstellen
64
+ self.tools = self._create_vm_tools()
65
+ llm_with_tools = self.llm.bind_tools(self.tools)
66
+
67
+ system_prompt = """Du bist ein autonomer Pentest-Agent mit VM-Integration.
68
+
69
+ Deine Aufgabe:
70
+ 1. Führe alle Tests in einer isolierten VM durch
71
+ 2. Nutze Snapshots für Clean-State-Workflows
72
+ 3. Dokumentiere alle Findings strukturiert
73
+ 4. Fasse Ergebnisse am Ende zusammen
74
+
75
+ SICHERHEIT:
76
+ - Alle Scans laufen in der VM 'kali-pentest'
77
+ - Snapshots werden automatisch verwaltet
78
+ - Keine Auswirkungen auf das Host-System
79
+
80
+ Wenn fertig, gib eine finale Zusammenfassung."""
81
+
82
+ def agent_node(state: AgentState) -> AgentState:
83
+ if state["iteration"] >= state["max_iterations"]:
84
+ return {
85
+ **state,
86
+ "messages": state["messages"] + [
87
+ AIMessage(content="Maximale Iterationen erreicht.")
88
+ ],
89
+ "status": "completed"
90
+ }
91
+
92
+ messages = [SystemMessage(content=system_prompt)] + state["messages"]
93
+ response = llm_with_tools.invoke(messages)
94
+
95
+ return {
96
+ **state,
97
+ "messages": [response],
98
+ "iteration": state["iteration"] + 1
99
+ }
100
+
101
+ def tools_node(state: AgentState) -> AgentState:
102
+ last_message = state["messages"][-1]
103
+
104
+ if not hasattr(last_message, 'tool_calls') or not last_message.tool_calls:
105
+ return state
106
+
107
+ tool_messages = []
108
+ new_findings = []
109
+
110
+ for tool_call in last_message.tool_calls:
111
+ tool_name = tool_call["name"]
112
+ args = tool_call["args"]
113
+ tool_id = tool_call["id"]
114
+
115
+ logger.info(f"VM-Tool-Aufruf: {tool_name}")
116
+
117
+ try:
118
+ tool_func = {t.name: t for t in self.tools}.get(tool_name)
119
+ if tool_func:
120
+ result = tool_func.invoke(args)
121
+ tool_messages.append(ToolMessage(content=result, tool_call_id=tool_id))
122
+ new_findings.append({
123
+ "tool": tool_name,
124
+ "args": args,
125
+ "result": result
126
+ })
127
+ else:
128
+ tool_messages.append(ToolMessage(
129
+ content=f"Tool {tool_name} nicht gefunden",
130
+ tool_call_id=tool_id
131
+ ))
132
+ except Exception as e:
133
+ error_msg = f"VM-Tool-Fehler: {str(e)}"
134
+ logger.error(error_msg)
135
+ tool_messages.append(ToolMessage(content=error_msg, tool_call_id=tool_id))
136
+
137
+ return {
138
+ **state,
139
+ "messages": tool_messages,
140
+ "findings": state["findings"] + new_findings
141
+ }
142
+
143
+ def should_continue(state: AgentState):
144
+ last_message = state["messages"][-1]
145
+
146
+ if state.get("status") == "completed":
147
+ return "end"
148
+
149
+ if hasattr(last_message, 'tool_calls') and last_message.tool_calls:
150
+ return "tools"
151
+
152
+ if isinstance(last_message, ToolMessage):
153
+ return "agent"
154
+
155
+ return "end"
156
+
157
+ workflow = StateGraph(AgentState)
158
+ workflow.add_node("agent", agent_node)
159
+ workflow.add_node("tools", tools_node)
160
+ workflow.add_edge(START, "agent")
161
+ workflow.add_conditional_edges("agent", should_continue,
162
+ {"tools": "tools", "agent": "agent", "end": END})
163
+ workflow.add_conditional_edges("tools", should_continue,
164
+ {"tools": "tools", "agent": "agent", "end": END})
165
+
166
+ checkpointer = MemorySaver()
167
+ return workflow.compile(checkpointer=checkpointer)
168
+
169
+ def _create_vm_tools(self) -> List:
170
+ """Erstellt VM-basierte Tools"""
171
+ from langchain_core.tools import tool
172
+
173
+ config = self.vm_config
174
+
175
+ @tool
176
+ def vm_nmap_scan(target: str, ports: str = "top-100") -> str:
177
+ """Scannt Ports in VM mit Nmap"""
178
+ if not self.session_id:
179
+ return "Keine aktive Session"
180
+
181
+ port_arg = "--top-ports 100" if ports == "top-100" else f"-p {ports}"
182
+ exit_code, stdout, stderr = self.sandbox.execute_tool(
183
+ self.session_id, "nmap", f"{port_arg} {target}",
184
+ config.vm_username, config.vm_password
185
+ )
186
+ return stdout if exit_code == 0 else stderr
187
+
188
+ @tool
189
+ def vm_nuclei_scan(target: str, severity: str = "critical,high") -> str:
190
+ """Scannt nach CVEs in VM mit Nuclei"""
191
+ if not self.session_id:
192
+ return "Keine aktive Session"
193
+
194
+ exit_code, stdout, stderr = self.sandbox.execute_tool(
195
+ self.session_id, "nuclei",
196
+ f"-u {target} -s {severity}",
197
+ config.vm_username, config.vm_password
198
+ )
199
+ return stdout if exit_code == 0 else stderr
200
+
201
+ @tool
202
+ def vm_gobuster_scan(target: str, wordlist: str = "common.txt") -> str:
203
+ """Directory Enumeration in VM mit Gobuster"""
204
+ if not self.session_id:
205
+ return "Keine aktive Session"
206
+
207
+ exit_code, stdout, stderr = self.sandbox.execute_tool(
208
+ self.session_id, "gobuster",
209
+ f"dir -u {target} -w /usr/share/wordlists/dirb/{wordlist}",
210
+ config.vm_username, config.vm_password
211
+ )
212
+ return stdout if exit_code == 0 else stderr
213
+
214
+ @tool
215
+ def restore_vm_snapshot(snapshot_name: str = "clean_state") -> str:
216
+ """Stellt VM-Snapshot wieder her"""
217
+ success = self.vbox.restore_snapshot(config.vm_name, snapshot_name)
218
+ return f"Snapshot {snapshot_name} wiederhergestellt" if success else "Fehler"
219
+
220
+ return [vm_nmap_scan, vm_nuclei_scan, vm_gobuster_scan, restore_vm_snapshot]
221
+
222
+ def run(self, target: str, objective: str = "comprehensive scan") -> dict:
223
+ """Führt VM-basierten Pentest durch"""
224
+
225
+ # VM Session starten
226
+ if self.vm_config.use_vm:
227
+ import uuid
228
+ self.session_id = f"vm_pentest_{uuid.uuid4().hex[:8]}"
229
+
230
+ logger.info(f"Starte VM-Session: {self.session_id}")
231
+
232
+ if self.vm_config.auto_restore_snapshot:
233
+ logger.info("Stelle clean_state Snapshot wieder her...")
234
+ self.vbox.restore_snapshot(self.vm_config.vm_name, "clean_state")
235
+
236
+ if not self.sandbox.create_session(self.session_id, self.vm_config.vm_name):
237
+ raise RuntimeError("Konnte VM-Session nicht starten")
238
+
239
+ try:
240
+ # Parent run aufrufen
241
+ initial_state = {
242
+ "messages": [HumanMessage(content=f"{objective} on {target}")],
243
+ "findings": [],
244
+ "target": target,
245
+ "iteration": 0,
246
+ "max_iterations": self.config.max_iterations,
247
+ "status": "running"
248
+ }
249
+
250
+ result = self.graph.invoke(
251
+ initial_state,
252
+ config={"configurable": {"thread_id": self.session_id}}
253
+ )
254
+
255
+ return {
256
+ "findings": result["findings"],
257
+ "final_message": result["messages"][-1].content if result["messages"] else "",
258
+ "iterations": result["iteration"],
259
+ "status": result["status"],
260
+ "target": target,
261
+ "session_id": self.session_id
262
+ }
263
+
264
+ finally:
265
+ # Aufräumen
266
+ if self.session_id and self.vm_config.use_vm:
267
+ logger.info("Beende VM-Session...")
268
+ self.sandbox.end_session(self.session_id)
269
+ self.session_id = None
270
+
271
+
272
+ # Factory
273
+ def get_vm_agent(config: VMAgentConfig = None) -> VMReActAgent:
274
+ """Gibt VM-basierten Agent zurück"""
275
+ return VMReActAgent(config)
276
+
277
+
278
+ if __name__ == "__main__":
279
+ logging.basicConfig(level=logging.INFO)
280
+
281
+ config = VMAgentConfig(
282
+ use_vm=True,
283
+ vm_name="kali-pentest",
284
+ max_iterations=5,
285
+ auto_restore_snapshot=True
286
+ )
287
+
288
+ agent = VMReActAgent(config)
289
+ result = agent.run("scanme.nmap.org", "Port scan and vulnerability assessment")
290
+
291
+ print("\n" + "=" * 70)
292
+ print("VM-BASIERTER PENTEST ABGESCHLOSSEN")
293
+ print("=" * 70)
294
+ print(f"Session: {result.get('session_id')}")
295
+ print(f"Iterations: {result['iterations']}")
296
+ print(f"Findings: {len(result['findings'])}")
297
+ print("\nFinal Analysis:")
298
+ print(result['final_message'][:500])
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Research Agent - Specializes in reconnaissance and information gathering
4
+ Part of the Multi-Agent Collaboration System
5
+ Author: SHAdd0WTAka
6
+ """
7
+
8
+ import asyncio
9
+ import logging
10
+ from typing import Any, Dict, List
11
+
12
+ from modules.cve_database import CVEDatabase
13
+ from modules.sql_injection_db import SQLInjectionDatabase
14
+
15
+ from .agent_base import AgentMessage, AgentRole, BaseAgent
16
+
17
+ logger = logging.getLogger("ZenAI.Agents")
18
+
19
+
20
+ class ResearchAgent(BaseAgent):
21
+ """
22
+ Research Agent - Gathers information, performs reconnaissance
23
+ Can research CVEs, exploits, techniques, and targets
24
+ """
25
+
26
+ def __init__(self, name: str, orchestrator=None, zen_orchestrator=None):
27
+ super().__init__(name, AgentRole.RESEARCHER, orchestrator)
28
+ self.zen_orchestrator = zen_orchestrator # LLM orchestrator
29
+ self.cve_db = CVEDatabase()
30
+ self.sqli_db = SQLInjectionDatabase()
31
+ self.current_research = {}
32
+
33
+ # Register message handlers
34
+ self.register_handler("research_task", self._handle_research_task)
35
+ self.register_handler("request_info", self._handle_info_request)
36
+ self.register_handler("findings", self._handle_findings)
37
+
38
+ async def _handle_research_task(self, msg: AgentMessage):
39
+ """Handle incoming research tasks"""
40
+ logger.info(f"[ResearchAgent:{self.name}] Received research task")
41
+
42
+ task_context = msg.context.get("pentest_context", {})
43
+ thread_id = msg.context.get("thread_id", "unknown")
44
+
45
+ # Acknowledge receipt
46
+ await self.send_message(
47
+ content=f"Starting research on {task_context.get('target', 'unknown target')}",
48
+ recipient=msg.sender,
49
+ msg_type="research_status",
50
+ context={"thread_id": thread_id, "status": "started"},
51
+ )
52
+
53
+ # Perform research
54
+ findings = await self._perform_research(task_context)
55
+
56
+ # Share findings with all agents
57
+ await self.send_message(
58
+ content=f"Research complete. Found {len(findings)} relevant items.",
59
+ recipient="all",
60
+ msg_type="findings",
61
+ priority=2,
62
+ context={
63
+ "thread_id": thread_id,
64
+ "findings": findings,
65
+ "researcher": self.name,
66
+ },
67
+ )
68
+
69
+ # Update shared context
70
+ self.update_context(f"research_{thread_id}", findings, share=True)
71
+
72
+ async def _handle_info_request(self, msg: AgentMessage):
73
+ """Handle requests for specific information"""
74
+ request_type = msg.context.get("info_type")
75
+ query = msg.content
76
+
77
+ logger.info(f"[ResearchAgent:{self.name}] Info request: {request_type}")
78
+
79
+ result = None
80
+
81
+ if request_type == "cve":
82
+ result = self.cve_db.search_cve(query)
83
+ elif request_type == "ransomware":
84
+ result = self.cve_db.search_ransomware(query)
85
+ elif request_type == "sqli_payload":
86
+ db_type = msg.context.get("db_type")
87
+ result = self.sqli_db.get_payloads(db_type=db_type)
88
+
89
+ if result:
90
+ await self.send_message(
91
+ content=f"Found information about {query}",
92
+ recipient=msg.sender,
93
+ msg_type="response",
94
+ context={"result": result, "query": query},
95
+ )
96
+
97
+ async def _handle_findings(self, msg: AgentMessage):
98
+ """Handle findings from other agents - cross-reference with research"""
99
+ findings = msg.context.get("findings", {})
100
+
101
+ # If findings contain CVEs, enrich them with database info
102
+ if "cves" in findings:
103
+ enriched = []
104
+ for cve_id in findings["cves"]:
105
+ cve_info = self.cve_db.search_cve(cve_id)
106
+ if cve_info:
107
+ enriched.append(cve_info)
108
+
109
+ if enriched:
110
+ await self.send_message(
111
+ content=f"Enriched {len(enriched)} CVEs with database information",
112
+ recipient=msg.sender,
113
+ msg_type="enrichment",
114
+ context={"enriched_cves": enriched},
115
+ )
116
+
117
+ async def _perform_research(self, context: Dict) -> List[Dict]:
118
+ """Perform actual research based on context"""
119
+ findings = []
120
+ target = context.get("target", "")
121
+
122
+ # Research 1: Check for known CVEs related to target tech
123
+ technologies = context.get("technologies", [])
124
+ for tech in technologies:
125
+ # Use LLM to find relevant CVEs
126
+ if self.zen_orchestrator:
127
+ prompt = f"""
128
+ List known CVEs for {tech} that are commonly exploited by ransomware.
129
+ Return CVE IDs only, one per line.
130
+ """
131
+ response = await self.zen_orchestrator.process(prompt)
132
+
133
+ # Parse CVEs from response
134
+ import re
135
+
136
+ cves = re.findall(r"CVE-\d{4}-\d{4,}", response.content)
137
+
138
+ for cve_id in cves[:5]: # Limit to top 5
139
+ cve_data = self.cve_db.search_cve(cve_id)
140
+ if cve_data:
141
+ findings.append(
142
+ {"type": "cve", "data": cve_data, "source": "llm_research"}
143
+ )
144
+
145
+ # Research 2: Check for ransomware using these technologies
146
+ ransomware = self.cve_db.list_all_ransomware()
147
+ for rw in ransomware[:3]: # Check top 3
148
+ findings.append({"type": "ransomware", "data": rw, "source": "database"})
149
+
150
+ return findings
151
+
152
+ async def execute_task(self, task: Dict) -> Dict:
153
+ """Execute a research task"""
154
+ task_type = task.get("type", "")
155
+ context = task.get("context", {})
156
+
157
+ logger.info(f"[ResearchAgent:{self.name}] Executing task: {task_type}")
158
+
159
+ if task_type == "reconnaissance":
160
+ findings = await self._perform_research(context)
161
+
162
+ # Share with other agents
163
+ await self.send_message(
164
+ content="Reconnaissance findings ready",
165
+ recipient="role:analyst",
166
+ msg_type="findings",
167
+ context={"findings": findings},
168
+ )
169
+
170
+ return {
171
+ "status": "complete",
172
+ "findings_count": len(findings),
173
+ "agent": self.name,
174
+ }
175
+
176
+ return {"status": "unknown_task"}
api/__init__.py ADDED
@@ -0,0 +1,11 @@
1
+ """
2
+ Zen AI Pentest - REST API Module
3
+
4
+ A production-ready API for penetration testing operations.
5
+ Built with FastAPI for high performance and automatic documentation.
6
+
7
+ Author: SHAdd0WTAka + Kimi AI
8
+ """
9
+
10
+ __version__ = "1.0.0"
11
+ __all__ = ["app", "create_app"]
api/auth.py ADDED
@@ -0,0 +1,123 @@
1
+ """
2
+ JWT Authentication für Zen-AI-Pentest API
3
+ """
4
+
5
+ from datetime import datetime, timedelta
6
+ from typing import Optional, Dict
7
+ from jose import JWTError, jwt
8
+ from passlib.context import CryptContext
9
+ from fastapi import Depends, HTTPException, status
10
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
11
+
12
+ # Configuration
13
+ SECRET_KEY = "your-secret-key-here-change-in-production" # In production: env var
14
+ ALGORITHM = "HS256"
15
+ ACCESS_TOKEN_EXPIRE_MINUTES = 30
16
+
17
+ # Password hashing
18
+ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
19
+ security = HTTPBearer()
20
+
21
+ def verify_password(plain_password: str, hashed_password: str) -> bool:
22
+ """Verifiziert Passwort"""
23
+ return pwd_context.verify(plain_password, hashed_password)
24
+
25
+ def get_password_hash(password: str) -> str:
26
+ """Hashed Passwort"""
27
+ return pwd_context.hash(password)
28
+
29
+ def create_access_token(data: Dict, expires_delta: Optional[timedelta] = None) -> str:
30
+ """Erstellt JWT Token"""
31
+ to_encode = data.copy()
32
+ expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
33
+ to_encode.update({"exp": expire})
34
+ encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
35
+ return encoded_jwt
36
+
37
+ def decode_token(token: str) -> Optional[Dict]:
38
+ """Decodiert JWT Token"""
39
+ try:
40
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
41
+ return payload
42
+ except JWTError:
43
+ return None
44
+
45
+ async def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)) -> Dict:
46
+ """FastAPI Dependency für Token-Verifizierung"""
47
+ token = credentials.credentials
48
+ payload = decode_token(token)
49
+
50
+ if payload is None:
51
+ raise HTTPException(
52
+ status_code=status.HTTP_401_UNAUTHORIZED,
53
+ detail="Invalid authentication credentials",
54
+ headers={"WWW-Authenticate": "Bearer"},
55
+ )
56
+
57
+ # Check expiration
58
+ exp = payload.get("exp")
59
+ if exp and datetime.utcnow().timestamp() > exp:
60
+ raise HTTPException(
61
+ status_code=status.HTTP_401_UNAUTHORIZED,
62
+ detail="Token has expired",
63
+ headers={"WWW-Authenticate": "Bearer"},
64
+ )
65
+
66
+ return payload
67
+
68
+ def check_permissions(user: Dict, required_role: str) -> bool:
69
+ """Prüft ob User die benötigte Rolle hat"""
70
+ user_role = user.get("role", "viewer")
71
+
72
+ roles_hierarchy = {
73
+ "viewer": 1,
74
+ "operator": 2,
75
+ "admin": 3
76
+ }
77
+
78
+ user_level = roles_hierarchy.get(user_role, 0)
79
+ required_level = roles_hierarchy.get(required_role, 0)
80
+
81
+ return user_level >= required_level
82
+
83
+ async def require_admin(credentials: HTTPAuthorizationCredentials = Depends(security)) -> Dict:
84
+ """Erfordert Admin-Rolle"""
85
+ user = await verify_token(credentials)
86
+
87
+ if not check_permissions(user, "admin"):
88
+ raise HTTPException(
89
+ status_code=status.HTTP_403_FORBIDDEN,
90
+ detail="Admin privileges required"
91
+ )
92
+
93
+ return user
94
+
95
+ async def require_operator(credentials: HTTPAuthorizationCredentials = Depends(security)) -> Dict:
96
+ """Erfordert Operator oder höhere Rolle"""
97
+ user = await verify_token(credentials)
98
+
99
+ if not check_permissions(user, "operator"):
100
+ raise HTTPException(
101
+ status_code=status.HTTP_403_FORBIDDEN,
102
+ detail="Operator privileges required"
103
+ )
104
+
105
+ return user
106
+
107
+ # API Key Authentication (für CI/CD Integrationen)
108
+ API_KEYS = {} # In production: in DB speichern
109
+
110
+ def verify_api_key(api_key: str) -> Optional[Dict]:
111
+ """Verifiziert API Key"""
112
+ return API_KEYS.get(api_key)
113
+
114
+ def create_api_key(user_id: int, name: str) -> str:
115
+ """Erstellt neuen API Key"""
116
+ import secrets
117
+ key = secrets.token_urlsafe(32)
118
+ API_KEYS[key] = {
119
+ "user_id": user_id,
120
+ "name": name,
121
+ "created_at": datetime.utcnow().isoformat()
122
+ }
123
+ return key