it
This commit is contained in:
		
							parent
							
								
									2185177a84
								
							
						
					
					
						commit
						c91913fa13
					
				
							
								
								
									
										110
									
								
								app.py
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								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():
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user