This commit is contained in:
overcuriousity 2025-09-14 16:07:58 +02:00
parent 72f7056bc7
commit 3511f18f9a
7 changed files with 50 additions and 206 deletions

117
app.py
View File

@ -1,3 +1,5 @@
# dnsrecon-reduced/app.py
""" """
Flask application entry point for DNSRecon web interface. Flask application entry point for DNSRecon web interface.
Provides REST API endpoints and serves the web interface with user session support. Provides REST API endpoints and serves the web interface with user session support.
@ -321,12 +323,18 @@ def export_results():
@app.route('/api/providers', methods=['GET']) @app.route('/api/providers', methods=['GET'])
def get_providers(): def get_providers():
"""Get information about available providers for the user session.""" """Get information about available providers for the user session."""
print("=== API: /api/providers called ===")
try: try:
# Get user-specific scanner # Get user-specific scanner
user_session_id, scanner = get_user_scanner() user_session_id, scanner = get_user_scanner()
if scanner:
completed_tasks = scanner.indicators_completed
enqueued_tasks = len(scanner.task_queue)
print(f"DEBUG: Tasks - Completed: {completed_tasks}, Enqueued: {enqueued_tasks}")
else:
print("DEBUG: No active scanner session found.")
provider_info = scanner.get_provider_info() provider_info = scanner.get_provider_info()
return jsonify({ return jsonify({
@ -401,113 +409,6 @@ def set_api_keys():
'error': f'Internal server error: {str(e)}' 'error': f'Internal server error: {str(e)}'
}), 500 }), 500
# TODO buggy, remove
@app.route('/api/session/info', methods=['GET'])
def get_session_info():
"""Get information about the current user session."""
try:
user_session_id, scanner = get_user_scanner()
session_info = session_manager.get_session_info(user_session_id)
return jsonify({
'success': True,
'session_info': session_info
})
except Exception as e:
print(f"ERROR: Exception in get_session_info endpoint: {e}")
traceback.print_exc()
return jsonify({
'success': False,
'error': f'Internal server error: {str(e)}'
}), 500
@app.route('/api/session/terminate', methods=['POST'])
def terminate_session():
"""Terminate the current user session."""
try:
user_session_id = session.get('dnsrecon_session_id')
if user_session_id:
success = session_manager.terminate_session(user_session_id)
# Clear Flask session
session.pop('dnsrecon_session_id', None)
return jsonify({
'success': success,
'message': 'Session terminated' if success else 'Session not found'
})
else:
return jsonify({
'success': False,
'error': 'No active session to terminate'
}), 400
except Exception as e:
print(f"ERROR: Exception in terminate_session endpoint: {e}")
traceback.print_exc()
return jsonify({
'success': False,
'error': f'Internal server error: {str(e)}'
}), 500
# TODO remove
@app.route('/api/admin/sessions', methods=['GET'])
def list_sessions():
"""Admin endpoint to list all active sessions."""
try:
sessions = session_manager.list_active_sessions()
stats = session_manager.get_statistics()
return jsonify({
'success': True,
'sessions': sessions,
'statistics': stats
})
except Exception as e:
print(f"ERROR: Exception in list_sessions endpoint: {e}")
traceback.print_exc()
return jsonify({
'success': False,
'error': f'Internal server error: {str(e)}'
}), 500
# TODO remove
@app.route('/api/health', methods=['GET'])
def health_check():
"""Health check endpoint."""
try:
# Get session stats
session_stats = session_manager.get_statistics()
return jsonify({
'success': True,
'status': 'healthy',
'timestamp': datetime.now(timezone.utc).isoformat(),
'version': '1.0.0-phase2',
'phase': 2,
'features': {
'multi_provider': True,
'concurrent_processing': True,
'real_time_updates': True,
'api_key_management': True,
'visualization': True,
'retry_logic': True,
'user_sessions': True,
'session_isolation': True
},
'session_statistics': session_stats
})
except Exception as e:
print(f"ERROR: Exception in health_check endpoint: {e}")
return jsonify({
'success': False,
'error': f'Health check failed: {str(e)}'
}), 500
@app.errorhandler(404) @app.errorhandler(404)
def not_found(error): def not_found(error):
"""Handle 404 errors.""" """Handle 404 errors."""

View File

@ -703,7 +703,6 @@ class Scanner:
'current_depth': self.current_depth, 'current_depth': self.current_depth,
'max_depth': self.max_depth, 'max_depth': self.max_depth,
'current_indicator': self.current_indicator, 'current_indicator': self.current_indicator,
'total_indicators_found': self.total_indicators_found,
'indicators_processed': self.indicators_processed, 'indicators_processed': self.indicators_processed,
'indicators_completed': self.indicators_completed, 'indicators_completed': self.indicators_completed,
'tasks_re_enqueued': self.tasks_re_enqueued, 'tasks_re_enqueued': self.tasks_re_enqueued,
@ -721,7 +720,6 @@ class Scanner:
'current_depth': 0, 'current_depth': 0,
'max_depth': 0, 'max_depth': 0,
'current_indicator': '', 'current_indicator': '',
'total_indicators_found': 0,
'indicators_processed': 0, 'indicators_processed': 0,
'indicators_completed': 0, 'indicators_completed': 0,
'tasks_re_enqueued': 0, 'tasks_re_enqueued': 0,
@ -732,10 +730,11 @@ class Scanner:
} }
def _calculate_progress(self) -> float: def _calculate_progress(self) -> float:
"""Calculate scan progress percentage.""" """Calculate scan progress percentage based on task completion."""
if self.total_indicators_found == 0: total_tasks = self.indicators_completed + len(self.task_queue)
if total_tasks == 0:
return 0.0 return 0.0
return min(100.0, (self.indicators_processed / self.total_indicators_found) * 100) return min(100.0, (self.indicators_completed / total_tasks) * 100)
def get_graph_data(self) -> Dict[str, Any]: def get_graph_data(self) -> Dict[str, Any]:
"""Get current graph data for visualization.""" """Get current graph data for visualization."""
@ -798,9 +797,6 @@ class Scanner:
'statistics': live_provider.get_statistics() if live_provider else temp_provider.get_statistics(), 'statistics': live_provider.get_statistics() if live_provider else temp_provider.get_statistics(),
'enabled': self.config.is_provider_enabled(provider_name), 'enabled': self.config.is_provider_enabled(provider_name),
'rate_limit': self.config.get_rate_limit(provider_name), 'rate_limit': self.config.get_rate_limit(provider_name),
'task_queue_size': len(self.task_queue),
'tasks_completed': self.indicators_completed,
'tasks_re_enqueued': self.tasks_re_enqueued,
} }
except Exception as e: except Exception as e:
print(f"✗ Failed to get info for provider from {filename}: {e}") print(f"✗ Failed to get info for provider from {filename}: {e}")

View File

@ -355,31 +355,6 @@ class SessionManager:
time.sleep(300) # Sleep for 5 minutes time.sleep(300) # Sleep for 5 minutes
def list_active_sessions(self) -> List[Dict[str, Any]]:
"""List all active sessions for admin purposes."""
try:
session_keys = self.redis_client.keys("dnsrecon:session:*")
sessions = []
for session_key in session_keys:
session_id = session_key.decode('utf-8').split(':')[-1]
session_data = self._get_session_data(session_id)
if session_data:
scanner = session_data.get('scanner')
sessions.append({
'session_id': session_id,
'created_at': session_data.get('created_at'),
'last_activity': session_data.get('last_activity'),
'scanner_status': scanner.status if scanner else 'unknown',
'current_target': scanner.current_target if scanner else None
})
return sessions
except Exception as e:
print(f"ERROR: Failed to list active sessions: {e}")
return []
def get_statistics(self) -> Dict[str, Any]: def get_statistics(self) -> Dict[str, Any]:
"""Get session manager statistics.""" """Get session manager statistics."""
try: try:

View File

@ -272,8 +272,24 @@ input[type="text"]:focus, select:focus {
text-shadow: 0 0 3px rgba(0, 255, 65, 0.3); text-shadow: 0 0 3px rgba(0, 255, 65, 0.3);
} }
.progress-container {
padding: 0 1.5rem 1.5rem;
}
.progress-info {
display: flex;
justify-content: space-between;
font-size: 0.8rem;
color: #999;
margin-bottom: 0.5rem;
}
#progress-compact {
color: #00ff41;
font-weight: 500;
}
.progress-bar { .progress-bar {
margin: 1rem 1.5rem;
height: 8px; height: 8px;
background-color: #1a1a1a; background-color: #1a1a1a;
border: 1px solid #444; border: 1px solid #444;

View File

@ -216,12 +216,8 @@ class GraphManager {
} }
}); });
// FIX: Comment out the problematic context menu handler
this.network.on('oncontext', (params) => { this.network.on('oncontext', (params) => {
params.event.preventDefault(); params.event.preventDefault();
// if (params.nodes.length > 0) {
// this.showNodeContextMenu(params.pointer.DOM, params.nodes[0]);
// }
}); });
// Stabilization events with progress // Stabilization events with progress

View File

@ -1,7 +1,6 @@
/** /**
* Main application logic for DNSRecon web interface * Main application logic for DNSRecon web interface
* Handles UI interactions, API communication, and data flow * Handles UI interactions, API communication, and data flow
* DEBUG VERSION WITH EXTRA LOGGING
*/ */
class DNSReconApp { class DNSReconApp {
@ -61,12 +60,8 @@ class DNSReconApp {
scanStatus: document.getElementById('scan-status'), scanStatus: document.getElementById('scan-status'),
targetDisplay: document.getElementById('target-display'), targetDisplay: document.getElementById('target-display'),
depthDisplay: document.getElementById('depth-display'), depthDisplay: document.getElementById('depth-display'),
progressDisplay: document.getElementById('progress-display'),
indicatorsDisplay: document.getElementById('indicators-display'),
relationshipsDisplay: document.getElementById('relationships-display'), relationshipsDisplay: document.getElementById('relationships-display'),
taskQueueDisplay: document.getElementById('task-queue-display'), progressCompact: document.getElementById('progress-compact'),
tasksCompletedDisplay: document.getElementById('tasks-completed-display'),
tasksReEnqueuedDisplay: document.getElementById('tasks-re-enqueued-display'),
progressFill: document.getElementById('progress-fill'), progressFill: document.getElementById('progress-fill'),
// Provider elements // Provider elements
@ -545,25 +540,18 @@ class DNSReconApp {
if (this.elements.depthDisplay) { if (this.elements.depthDisplay) {
this.elements.depthDisplay.textContent = `${status.current_depth}/${status.max_depth}`; this.elements.depthDisplay.textContent = `${status.current_depth}/${status.max_depth}`;
} }
if (this.elements.progressDisplay) {
this.elements.progressDisplay.textContent = `${status.progress_percentage.toFixed(1)}%`;
}
if (this.elements.indicatorsDisplay) {
this.elements.indicatorsDisplay.textContent = status.indicators_processed || 0;
}
if (this.elements.taskQueueDisplay) {
this.elements.taskQueueDisplay.textContent = status.task_queue_size || 0;
}
if (this.elements.tasksCompletedDisplay) {
this.elements.tasksCompletedDisplay.textContent = status.indicators_completed || 0;
}
if (this.elements.tasksReEnqueuedDisplay) {
this.elements.tasksReEnqueuedDisplay.textContent = status.tasks_re_enqueued || 0;
}
// Update progress bar with smooth animation // Update progress bar and compact display
if (this.elements.progressFill) { if (this.elements.progressFill) {
this.elements.progressFill.style.width = `${status.progress_percentage}%`; const completed = status.indicators_completed || 0;
const enqueued = status.task_queue_size || 0;
const totalTasks = completed + enqueued;
const progressPercentage = totalTasks > 0 ? (completed / totalTasks) * 100 : 0;
this.elements.progressFill.style.width = `${progressPercentage}%`;
if (this.elements.progressCompact) {
this.elements.progressCompact.textContent = `${completed}/${totalTasks} - ${Math.round(progressPercentage)}%`;
}
// Add pulsing animation for active scans // Add pulsing animation for active scans
if (status.status === 'running') { if (status.status === 'running') {
@ -802,20 +790,6 @@ class DNSReconApp {
<span class="provider-stat-value">${info.rate_limit}/min</span> <span class="provider-stat-value">${info.rate_limit}/min</span>
</div> </div>
</div> </div>
<div class="provider-task-stats">
<div class="provider-stat">
<span class="provider-stat-label">Task Queue:</span>
<span class="provider-stat-value">${info.task_queue_size || 0}</span>
</div>
<div class="provider-stat">
<span class="provider-stat-label">Tasks Completed:</span>
<span class="provider-stat-value">${info.tasks_completed || 0}</span>
</div>
<div class="provider-stat">
<span class="provider-stat-label">Tasks Re-enqueued:</span>
<span class="provider-stat-value">${info.tasks_re_enqueued || 0}</span>
</div>
</div>
`; `;
this.elements.providerList.appendChild(providerItem); this.elements.providerList.appendChild(providerItem);

View File

@ -90,34 +90,20 @@
<span class="status-label">Depth:</span> <span class="status-label">Depth:</span>
<span id="depth-display" class="status-value">0/0</span> <span id="depth-display" class="status-value">0/0</span>
</div> </div>
<div class="status-row">
<span class="status-label">Progress:</span>
<span id="progress-display" class="status-value">0%</span>
</div>
<div class="status-row">
<span class="status-label">Indicators:</span>
<span id="indicators-display" class="status-value">0</span>
</div>
<div class="status-row"> <div class="status-row">
<span class="status-label">Relationships:</span> <span class="status-label">Relationships:</span>
<span id="relationships-display" class="status-value">0</span> <span id="relationships-display" class="status-value">0</span>
</div> </div>
<div class="status-row">
<span class="status-label">Task Queue:</span>
<span id="task-queue-display" class="status-value">0</span>
</div>
<div class="status-row">
<span class="status-label">Tasks Completed:</span>
<span id="tasks-completed-display" class="status-value">0</span>
</div>
<div class="status-row">
<span class="status-label">Tasks Re-enqueued:</span>
<span id="tasks-re-enqueued-display" class="status-value">0</span>
</div>
</div> </div>
<div class="progress-bar"> <div class="progress-container">
<div id="progress-fill" class="progress-fill"></div> <div class="progress-info">
<span id="progress-label">Progress:</span>
<span id="progress-compact">0/0</span>
</div>
<div class="progress-bar">
<div id="progress-fill" class="progress-fill"></div>
</div>
</div> </div>
</section> </section>