zen-ai-pentest 2.1.0__py3-none-any.whl → 2.3.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.
- api/auth.py +61 -7
- api/csrf_protection.py +286 -0
- api/main.py +79 -13
- api/rate_limiter.py +317 -0
- api/rate_limiter_v2.py +586 -0
- api/websocket_v2.py +181 -0
- autonomous/ki_analysis_agent.py +1033 -0
- benchmarks/__init__.py +12 -142
- benchmarks/agent_performance.py +374 -0
- benchmarks/api_performance.py +479 -0
- benchmarks/scan_performance.py +272 -0
- modules/agent_coordinator.py +255 -0
- modules/api_key_manager.py +501 -0
- modules/benchmark.py +706 -0
- modules/cve_updater.py +303 -0
- modules/false_positive_filter.py +149 -0
- modules/output_formats.py +1088 -0
- modules/report_export.py +207 -0
- modules/risk_scoring.py +206 -0
- {zen_ai_pentest-2.1.0.dist-info → zen_ai_pentest-2.3.0.dist-info}/METADATA +134 -289
- {zen_ai_pentest-2.1.0.dist-info → zen_ai_pentest-2.3.0.dist-info}/RECORD +25 -9
- {zen_ai_pentest-2.1.0.dist-info → zen_ai_pentest-2.3.0.dist-info}/WHEEL +0 -0
- {zen_ai_pentest-2.1.0.dist-info → zen_ai_pentest-2.3.0.dist-info}/entry_points.txt +0 -0
- {zen_ai_pentest-2.1.0.dist-info → zen_ai_pentest-2.3.0.dist-info}/licenses/LICENSE +0 -0
- {zen_ai_pentest-2.1.0.dist-info → zen_ai_pentest-2.3.0.dist-info}/top_level.txt +0 -0
api/websocket_v2.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WebSocket v2.0 - Real-time Updates
|
|
3
|
+
Q2 2026 Feature
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, Set
|
|
9
|
+
from fastapi import WebSocket, WebSocketDisconnect
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ConnectionManagerV2:
|
|
16
|
+
"""Advanced WebSocket connection manager with rooms"""
|
|
17
|
+
|
|
18
|
+
def __init__(self):
|
|
19
|
+
# Active connections by room
|
|
20
|
+
self.rooms: Dict[str, Set[WebSocket]] = {
|
|
21
|
+
"dashboard": set(),
|
|
22
|
+
"scans": set(),
|
|
23
|
+
"findings": set(),
|
|
24
|
+
"notifications": set()
|
|
25
|
+
}
|
|
26
|
+
# User connections
|
|
27
|
+
self.user_connections: Dict[str, WebSocket] = {}
|
|
28
|
+
|
|
29
|
+
async def connect(self, websocket: WebSocket, room: str = "dashboard", user_id: str = None):
|
|
30
|
+
"""Connect client to room"""
|
|
31
|
+
await websocket.accept()
|
|
32
|
+
|
|
33
|
+
if room in self.rooms:
|
|
34
|
+
self.rooms[room].add(websocket)
|
|
35
|
+
|
|
36
|
+
if user_id:
|
|
37
|
+
self.user_connections[user_id] = websocket
|
|
38
|
+
|
|
39
|
+
logger.info(f"Client connected to room: {room}")
|
|
40
|
+
|
|
41
|
+
# Send welcome message
|
|
42
|
+
await websocket.send_json({
|
|
43
|
+
"type": "connection",
|
|
44
|
+
"status": "connected",
|
|
45
|
+
"room": room,
|
|
46
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
def disconnect(self, websocket: WebSocket, room: str = None):
|
|
50
|
+
"""Disconnect client"""
|
|
51
|
+
if room and room in self.rooms:
|
|
52
|
+
self.rooms[room].discard(websocket)
|
|
53
|
+
else:
|
|
54
|
+
# Remove from all rooms
|
|
55
|
+
for room_set in self.rooms.values():
|
|
56
|
+
room_set.discard(websocket)
|
|
57
|
+
|
|
58
|
+
# Remove from user connections
|
|
59
|
+
for user_id, conn in list(self.user_connections.items()):
|
|
60
|
+
if conn == websocket:
|
|
61
|
+
del self.user_connections[user_id]
|
|
62
|
+
|
|
63
|
+
logger.info("Client disconnected")
|
|
64
|
+
|
|
65
|
+
async def broadcast_to_room(self, room: str, message: dict):
|
|
66
|
+
"""Broadcast message to all clients in room"""
|
|
67
|
+
if room not in self.rooms:
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
disconnected = set()
|
|
71
|
+
for connection in self.rooms[room]:
|
|
72
|
+
try:
|
|
73
|
+
await connection.send_json(message)
|
|
74
|
+
except Exception:
|
|
75
|
+
disconnected.add(connection)
|
|
76
|
+
|
|
77
|
+
# Clean up disconnected clients
|
|
78
|
+
for conn in disconnected:
|
|
79
|
+
self.rooms[room].discard(conn)
|
|
80
|
+
|
|
81
|
+
async def send_to_user(self, user_id: str, message: dict):
|
|
82
|
+
"""Send message to specific user"""
|
|
83
|
+
if user_id in self.user_connections:
|
|
84
|
+
try:
|
|
85
|
+
await self.user_connections[user_id].send_json(message)
|
|
86
|
+
except Exception:
|
|
87
|
+
del self.user_connections[user_id]
|
|
88
|
+
|
|
89
|
+
async def broadcast_scan_update(self, scan_id: str, status: str, progress: int = None):
|
|
90
|
+
"""Broadcast scan progress update"""
|
|
91
|
+
await self.broadcast_to_room("scans", {
|
|
92
|
+
"type": "scan_update",
|
|
93
|
+
"scan_id": scan_id,
|
|
94
|
+
"status": status,
|
|
95
|
+
"progress": progress,
|
|
96
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
async def broadcast_finding(self, finding: dict):
|
|
100
|
+
"""Broadcast new finding discovery"""
|
|
101
|
+
await self.broadcast_to_room("findings", {
|
|
102
|
+
"type": "new_finding",
|
|
103
|
+
"finding": finding,
|
|
104
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
async def broadcast_notification(self, title: str, message: str, severity: str = "info"):
|
|
108
|
+
"""Broadcast system notification"""
|
|
109
|
+
await self.broadcast_to_room("notifications", {
|
|
110
|
+
"type": "notification",
|
|
111
|
+
"title": title,
|
|
112
|
+
"message": message,
|
|
113
|
+
"severity": severity,
|
|
114
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
def get_room_stats(self) -> dict:
|
|
118
|
+
"""Get connection statistics"""
|
|
119
|
+
return {
|
|
120
|
+
room: len(connections)
|
|
121
|
+
for room, connections in self.rooms.items()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Global manager instance
|
|
126
|
+
manager_v2 = ConnectionManagerV2()
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
async def websocket_dashboard_endpoint(websocket: WebSocket):
|
|
130
|
+
"""Dashboard real-time updates"""
|
|
131
|
+
await manager_v2.connect(websocket, room="dashboard")
|
|
132
|
+
try:
|
|
133
|
+
while True:
|
|
134
|
+
# Receive ping from client
|
|
135
|
+
data = await websocket.receive_text()
|
|
136
|
+
message = json.loads(data)
|
|
137
|
+
|
|
138
|
+
if message.get("action") == "ping":
|
|
139
|
+
await websocket.send_json({
|
|
140
|
+
"type": "pong",
|
|
141
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
except WebSocketDisconnect:
|
|
145
|
+
manager_v2.disconnect(websocket, room="dashboard")
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
async def websocket_scans_endpoint(websocket: WebSocket):
|
|
149
|
+
"""Scan progress real-time updates"""
|
|
150
|
+
await manager_v2.connect(websocket, room="scans")
|
|
151
|
+
try:
|
|
152
|
+
while True:
|
|
153
|
+
data = await websocket.receive_text()
|
|
154
|
+
# Handle scan subscription requests
|
|
155
|
+
message = json.loads(data)
|
|
156
|
+
|
|
157
|
+
if message.get("action") == "subscribe_scan":
|
|
158
|
+
scan_id = message.get("scan_id")
|
|
159
|
+
await websocket.send_json({
|
|
160
|
+
"type": "subscribed",
|
|
161
|
+
"scan_id": scan_id,
|
|
162
|
+
"message": f"Subscribed to scan {scan_id} updates"
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
except WebSocketDisconnect:
|
|
166
|
+
manager_v2.disconnect(websocket, room="scans")
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
async def websocket_notifications_endpoint(websocket: WebSocket, user_id: str = None):
|
|
170
|
+
"""User-specific notifications"""
|
|
171
|
+
await manager_v2.connect(websocket, room="notifications", user_id=user_id)
|
|
172
|
+
try:
|
|
173
|
+
while True:
|
|
174
|
+
data = await websocket.receive_text()
|
|
175
|
+
# Acknowledge receipt
|
|
176
|
+
await websocket.send_json({
|
|
177
|
+
"type": "ack",
|
|
178
|
+
"received": True
|
|
179
|
+
})
|
|
180
|
+
except WebSocketDisconnect:
|
|
181
|
+
manager_v2.disconnect(websocket, room="notifications")
|