From c91913fa137173434bf5767cf9d91307c37ed8bd Mon Sep 17 00:00:00 2001 From: overcuriousity Date: Sun, 14 Sep 2025 14:28:04 +0200 Subject: [PATCH] it --- app.py | 110 +++++++++++-------------------------- core/scanner.py | 17 +++--- providers/base_provider.py | 1 - 3 files changed, 42 insertions(+), 86 deletions(-) diff --git a/app.py b/app.py index e3e89be..d14bb6d 100644 --- a/app.py +++ b/app.py @@ -19,43 +19,30 @@ app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=2) # 2 hour session def get_user_scanner(): """ - User scanner retrieval with better error handling and debugging. + Retrieves the scanner for the current session, or creates a new + session and scanner if one doesn't exist. """ # Get current Flask session info for debugging current_flask_session_id = session.get('dnsrecon_session_id') - client_ip = request.remote_addr - user_agent = request.headers.get('User-Agent', '')[:100] # Truncate for logging # Try to get existing session if current_flask_session_id: existing_scanner = session_manager.get_session(current_flask_session_id) if existing_scanner: - # Ensure session ID is set - existing_scanner.session_id = current_flask_session_id return current_flask_session_id, existing_scanner - else: - print(f"Session {current_flask_session_id} not found in session manager") - # Create new session - print("Creating new session...") + # Create new session if none exists + print("Creating new session as none was found...") new_session_id = session_manager.create_session() new_scanner = session_manager.get_session(new_session_id) if not new_scanner: - print(f"ERROR: Failed to retrieve newly created session {new_session_id}") raise Exception("Failed to create new scanner session") # Store in Flask session session['dnsrecon_session_id'] = new_session_id session.permanent = True - # Ensure session ID is set on scanner - new_scanner.session_id = new_session_id - - print(f"Created new session: {new_session_id}") - print(f"New scanner status: {new_scanner.status}") - print("=== END SESSION DEBUG ===") - return new_session_id, new_scanner @app.route('/') @@ -67,101 +54,68 @@ def index(): @app.route('/api/scan/start', methods=['POST']) def start_scan(): """ - Start a new reconnaissance scan with immediate GUI feedback. + Start a new reconnaissance scan. Creates a new isolated scanner if + clear_graph is true, otherwise adds to the existing one. """ print("=== API: /api/scan/start called ===") try: - print("Getting JSON data from request...") data = request.get_json() - print(f"Request data: {data}") - if not data or 'target_domain' not in data: - print("ERROR: Missing target_domain in request") - return jsonify({ - 'success': False, - 'error': 'Missing target_domain in request' - }), 400 + return jsonify({'success': False, 'error': 'Missing target_domain in request'}), 400 target_domain = data['target_domain'].strip() max_depth = data.get('max_depth', config.default_recursion_depth) clear_graph = data.get('clear_graph', True) - print(f"Parsed - target_domain: '{target_domain}', max_depth: {max_depth}") + print(f"Parsed - target_domain: '{target_domain}', max_depth: {max_depth}, clear_graph: {clear_graph}") # Validation if not target_domain: - print("ERROR: Target domain cannot be empty") - return jsonify({ - 'success': False, - 'error': 'Target domain cannot be empty' - }), 400 + return jsonify({'success': False, 'error': 'Target domain cannot be empty'}), 400 + if not isinstance(max_depth, int) or not 1 <= max_depth <= 5: + return jsonify({'success': False, 'error': 'Max depth must be an integer between 1 and 5'}), 400 - if not isinstance(max_depth, int) or max_depth < 1 or max_depth > 5: - print(f"ERROR: Invalid max_depth: {max_depth}") - return jsonify({ - 'success': False, - 'error': 'Max depth must be an integer between 1 and 5' - }), 400 + user_session_id, scanner = None, None + + if clear_graph: + print("Clear graph requested: Creating a new, isolated scanner session.") + old_session_id = session.get('dnsrecon_session_id') + if old_session_id: + session_manager.terminate_session(old_session_id) + + user_session_id = session_manager.create_session() + session['dnsrecon_session_id'] = user_session_id + session.permanent = True + scanner = session_manager.get_session(user_session_id) + else: + print("Adding to existing graph: Reusing the current scanner session.") + user_session_id, scanner = get_user_scanner() + + if not scanner: + return jsonify({'success': False, 'error': 'Failed to get or create a scanner instance.'}), 500 - print("Validation passed, getting user scanner...") + print(f"Using scanner {id(scanner)} in session {user_session_id}") - # Get user-specific scanner - user_session_id, scanner = get_user_scanner() - - # Ensure session ID is properly set - if not scanner.session_id: - scanner.session_id = user_session_id - - print(f"Using session: {user_session_id}") - print(f"Scanner object ID: {id(scanner)}") - - # Start scan - print(f"Calling start_scan on scanner {id(scanner)}...") success = scanner.start_scan(target_domain, max_depth, clear_graph=clear_graph) - # Immediately update session state regardless of success - session_manager.update_session_scanner(user_session_id, scanner) - if success: - scan_session_id = scanner.logger.session_id - print(f"Scan started successfully with scan session ID: {scan_session_id}") return jsonify({ 'success': True, 'message': 'Scan started successfully', - 'scan_id': scan_session_id, + 'scan_id': scanner.logger.session_id, 'user_session_id': user_session_id, - 'scanner_status': scanner.status, - 'debug_info': { - 'scanner_object_id': id(scanner), - 'scanner_status': scanner.status - } }) else: - print("ERROR: Scanner returned False") - - # Provide more detailed error information - error_details = { - 'scanner_status': scanner.status, - 'scanner_object_id': id(scanner), - 'session_id': user_session_id, - 'providers_count': len(scanner.providers) if hasattr(scanner, 'providers') else 0 - } - return jsonify({ 'success': False, 'error': f'Failed to start scan (scanner status: {scanner.status})', - 'debug_info': error_details }), 409 except Exception as e: print(f"ERROR: Exception in start_scan endpoint: {e}") traceback.print_exc() - return jsonify({ - 'success': False, - 'error': f'Internal server error: {str(e)}' - }), 500 - + return jsonify({'success': False, 'error': f'Internal server error: {str(e)}'}), 500 @app.route('/api/scan/stop', methods=['POST']) def stop_scan(): diff --git a/core/scanner.py b/core/scanner.py index a366f72..fdf588e 100644 --- a/core/scanner.py +++ b/core/scanner.py @@ -198,7 +198,8 @@ class Scanner: if self.scan_thread and self.scan_thread.is_alive(): print("A previous scan thread is still alive. Sending termination signal and waiting...") self.stop_scan() - self.scan_thread.join(10.0) + # Wait for the thread to die, with a timeout + self.scan_thread.join(10.0) if self.scan_thread.is_alive(): print("ERROR: The previous scan thread is unresponsive and could not be stopped.") @@ -209,7 +210,8 @@ class Scanner: # Reset state for new scan self.status = ScanStatus.IDLE - self._update_session_state() # Update GUI immediately + # This update is crucial for the UI to reflect the reset before the new scan starts. + self._update_session_state() print("Scanner state is now clean for a new scan.") try: @@ -225,7 +227,7 @@ class Scanner: self.max_depth = max_depth self.current_depth = 0 - # Clear both local and Redis stop signals + # Clear both local and Redis stop signals for the new scan self.stop_event.clear() if self.session_id: from core.session_manager import session_manager @@ -235,14 +237,14 @@ class Scanner: self.indicators_processed = 0 self.current_indicator = self.current_target - # Update GUI with scan preparation + # Update GUI with scan preparation state self._update_session_state() # Start new forensic session print(f"Starting new forensic session for scanner {id(self)}...") self.logger = new_session() - # Start scan in separate thread + # Start scan in a separate thread print(f"Starting scan thread for scanner {id(self)}...") self.scan_thread = threading.Thread( target=self._execute_scan, @@ -258,7 +260,8 @@ class Scanner: print(f"ERROR: Exception in start_scan for scanner {id(self)}: {e}") traceback.print_exc() self.status = ScanStatus.FAILED - self._update_session_state() # Update failed status immediately + # Update GUI with failed status immediately + self._update_session_state() return False def _execute_scan(self, target_domain: str, max_depth: int) -> None: @@ -648,7 +651,7 @@ class Scanner: # Immediately update GUI with stopped status self._update_session_state() - # Cancel executor futures if running + # Aggressively shut down the executor and cancel all pending tasks if self.executor: print("Shutting down executor with immediate cancellation...") self.executor.shutdown(wait=False, cancel_futures=True) diff --git a/providers/base_provider.py b/providers/base_provider.py index 4d0f8e1..b5e10f8 100644 --- a/providers/base_provider.py +++ b/providers/base_provider.py @@ -348,7 +348,6 @@ class BaseProvider(ABC): return True return False - def _wait_with_cancellation_check(self) -> bool: """ Wait for rate limiting while aggressively checking for cancellation.