#!/usr/bin/env python3
"""
Script to add enhanced download functionality to DecentraBrowser
"""

import os
import sys
import re

def add_methods_to_main_window():
    """Add enhanced_download_file and related methods to MainWindow class."""
    
    # Find the main_window.py file
    main_window_path = os.path.join(os.getcwd(), "decentrabrowser", "client", "gui", "main_window.py")
    if not os.path.exists(main_window_path):
        print(f"Cannot find {main_window_path}")
        return False
    
    print(f"Found MainWindow class at: {main_window_path}")
    
    # Read the file
    with open(main_window_path, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Check if methods already exist
    if 'def enhanced_download_file' in content:
        print("Methods already exist in MainWindow")
        return True
    
    # Find the end of the MainWindow class
    match = re.search(r'class\s+MainWindow\([^)]*\):(.*?)(?=\n\S)', content, re.DOTALL)
    if not match:
        print("Could not find MainWindow class")
        return False
    
    class_end = match.end()
    
    # Create methods to add
    methods_to_add = """
    def enhanced_download_file(self, domain_name, file_name=None):
        \"\"\"
        Enhanced download method with automatic decryption and secure key management.
        
        Args:
            domain_name (str): The domain to download from
            file_name (str, optional): The file name to download
        \"\"\"
        try:
            # If file_name is not provided, get it from the selected file
            if file_name is None:
                selected_items = self.tbl_files.selectedItems()
                if not selected_items:
                    QMessageBox.warning(self, "Error", "No file selected for download")
                    return
                
                row = selected_items[0].row()
                file_name = self.tbl_files.item(row, 0).text()
                
                if not file_name:
                    QMessageBox.warning(self, "Error", "Invalid file selected")
                    return
            
            # Store the current domain for future reference
            self.current_domain_name = domain_name
            
            # Show downloading status
            self.statusBar().showMessage(f"Downloading {file_name} from {domain_name}...", 5000)
            
            # Ensure the file name has .enc extension for downloading
            download_file_name = file_name
            if not download_file_name.endswith('.enc'):
                download_file_name = f"{file_name}.enc"
            
            print(f"Downloading encrypted file: {download_file_name}")
            
            # Create downloads directory
            app_data_dir = os.path.join(os.path.expanduser("~"), ".decentrabrowser")
            downloads_dir = os.path.join(app_data_dir, 'downloads')
            os.makedirs(downloads_dir, exist_ok=True)
            
            # Get the IP and port for the domain
            success, result = self.network_client.resolve_domain(domain_name)
            if not success:
                QMessageBox.warning(self, "Error", f"Could not resolve domain: {result}")
                self.statusBar().showMessage("Download failed: Could not resolve domain", 5000)
                return
            
            ip, port = result
            
            # Construct the download URL
            file_url = f"http://{ip}:{port}/file/{download_file_name}"
            print(f"Download URL: {file_url}")
            
            try:
                # Download the encrypted file
                import requests
                response = requests.get(file_url, stream=True, timeout=30)
                
                if response.status_code == 200:
                    # Save the encrypted file
                    encrypted_file_path = os.path.join(downloads_dir, download_file_name)
                    with open(encrypted_file_path, 'wb') as f:
                        for chunk in response.iter_content(chunk_size=8192):
                            if chunk:
                                f.write(chunk)
                    
                    print(f"Encrypted file downloaded to: {encrypted_file_path}")
                    
                    # Request the decryption key
                    self.statusBar().showMessage("Requesting decryption key...", 3000)
                    
                    # Generate key request URL
                    key_url = f"http://{ip}:{port}/key/{download_file_name}"
                    key_request = self.request_decryption_key(key_url)
                    
                    if key_request[0]:  # Success
                        encrypted_key = key_request[1]
                        
                        # Process decryption with the received key
                        self.process_decryption(encrypted_file_path, encrypted_key, file_name)
                    else:
                        # Failed to get key, ask if user wants to decrypt manually
                        reply = QMessageBox.question(
                            self, 
                            "Key Request Failed", 
                            f"Could not get decryption key automatically: {key_request[1]}\n"
                            f"The encrypted file is saved at: {encrypted_file_path}\n\n"
                            f"Do you want to try manual decryption?",
                            QMessageBox.Yes | QMessageBox.No, 
                            QMessageBox.Yes
                        )
                        
                        if reply == QMessageBox.Yes and hasattr(self, 'decrypt_file'):
                            # Manual decryption
                            self.manual_decrypt_file(encrypted_file_path, file_name)
                        else:
                            # Keep encrypted file
                            QMessageBox.information(
                                self,
                                "Download Complete",
                                f"The encrypted file has been downloaded to:\n{encrypted_file_path}"
                            )
                            self.statusBar().showMessage("File downloaded but not decrypted", 5000)
                else:
                    # Try once more without .enc if file not found
                    if response.status_code == 404 and download_file_name.endswith('.enc'):
                        print("File not found with .enc extension, trying without...")
                        plain_file_url = f"http://{ip}:{port}/file/{file_name}"
                        response = requests.get(plain_file_url, stream=True, timeout=30)
                        
                        if response.status_code == 200:
                            # File exists without encryption
                            file_path = os.path.join(downloads_dir, file_name)
                            with open(file_path, 'wb') as f:
                                for chunk in response.iter_content(chunk_size=8192):
                                    if chunk:
                                        f.write(chunk)
                            
                            QMessageBox.information(self, "Download Complete", 
                                                 f"The file is not encrypted and has been downloaded to:\n{file_path}")
                            self.statusBar().showMessage(f"File downloaded to: {file_path}", 5000)
                            
                            # Ask if user wants to open the file
                            reply = QMessageBox.question(
                                self, 
                                "File Downloaded", 
                                "Do you want to open the file now?",
                                QMessageBox.Yes | QMessageBox.No, 
                                QMessageBox.Yes
                            )
                            
                            if reply == QMessageBox.Yes:
                                try:
                                    import subprocess
                                    if sys.platform == 'win32':
                                        os.startfile(file_path)
                                    elif sys.platform == 'darwin':
                                        subprocess.call(['open', file_path])
                                    else:
                                        subprocess.call(['xdg-open', file_path])
                                except Exception as e:
                                    print(f"Error opening file: {str(e)}")
                                    QMessageBox.warning(self, "Error", f"Could not open file: {str(e)}")
                        else:
                            # File doesn't exist in any form
                            QMessageBox.warning(self, "Download Failed", 
                                             f"File not found (HTTP {response.status_code})")
                            self.statusBar().showMessage("Download failed: File not found", 5000)
                    else:
                        QMessageBox.warning(self, "Download Failed", 
                                          f"HTTP Error: {response.status_code}")
                        self.statusBar().showMessage(f"Download failed: HTTP {response.status_code}", 5000)
            except Exception as e:
                print(f"Error downloading file: {str(e)}")
                import traceback
                traceback.print_exc()
                QMessageBox.warning(self, "Error", f"Error downloading file: {str(e)}")
                self.statusBar().showMessage("Download failed", 5000)
                
        except Exception as e:
            print(f"Error in download process: {str(e)}")
            import traceback
            traceback.print_exc()
            QMessageBox.warning(self, "Error", f"Error in download process: {str(e)}")
            self.statusBar().showMessage("Download failed", 5000)
    
    def request_decryption_key(self, key_url):
        \"\"\"
        Request a decryption key from the server.
        The key will be encrypted with the user's public key.
        
        Args:
            key_url (str): URL to request the key from
            
        Returns:
            tuple: (success, result) where result is either the encrypted key or an error message
        \"\"\"
        try:
            print(f"Requesting key from: {key_url}")
            
            # First, ensure we have a keypair
            if not self.ensure_keypair():
                return False, "No keypair available"
            
            # Get our public key to send with the request
            public_key = self.load_public_key()
            if not public_key:
                return False, "Could not load public key"
            
            # Encode the public key for transmission
            import base64
            encoded_pubkey = base64.b64encode(public_key.encode()).decode()
            
            # Send the key request with our public key
            import requests
            headers = {'Content-Type': 'application/json'}
            data = {'public_key': encoded_pubkey}
            
            response = requests.post(key_url, json=data, headers=headers, timeout=30)
            
            if response.status_code == 200:
                try:
                    result = response.json()
                    if 'encrypted_key' in result:
                        return True, result['encrypted_key']
                    else:
                        return False, "Invalid response format"
                except Exception as e:
                    return False, f"Error parsing response: {str(e)}"
            else:
                return False, f"HTTP Error: {response.status_code}"
        
        except Exception as e:
            print(f"Error requesting key: {str(e)}")
            import traceback
            traceback.print_exc()
            return False, f"Error: {str(e)}"
    
    def process_decryption(self, encrypted_file_path, encrypted_key, original_file_name):
        \"\"\"
        Process the decryption of a file using the encrypted key.
        
        Args:
            encrypted_file_path (str): Path to the encrypted file
            encrypted_key (str): Encrypted key data
            original_file_name (str): Original file name without .enc
        \"\"\"
        try:
            # First decrypt the key using our private key
            decrypted_key = self.decrypt_key(encrypted_key)
            if not decrypted_key:
                QMessageBox.warning(self, "Decryption Error", 
                                  "Could not decrypt the file key. Please ensure you have the correct private key.")
                return
            
            # Ask user where to save the decrypted file
            save_dir = os.path.join(os.path.expanduser("~"), "Downloads")
            os.makedirs(save_dir, exist_ok=True)
            
            # Generate save path
            if original_file_name.endswith('.enc'):
                original_file_name = original_file_name[:-4]
                
            save_path, _ = QFileDialog.getSaveFileName(
                self, 
                "Save Decrypted File", 
                os.path.join(save_dir, original_file_name), 
                "All Files (*.*)"
            )
            
            if not save_path:
                self.statusBar().showMessage("Decryption cancelled", 3000)
                return
            
            # Show decryption status
            self.statusBar().showMessage("Decrypting file...", 3000)
            
            # Decrypt the file using the decrypted key
            success, result = self.decrypt_file_with_key(encrypted_file_path, save_path, decrypted_key)
            
            if success:
                QMessageBox.information(self, "Decryption Complete", 
                                      f"File successfully decrypted and saved to:\n{result}")
                self.statusBar().showMessage(f"File decrypted and saved to: {result}", 5000)
                
                # Ask if user wants to open the file
                reply = QMessageBox.question(
                    self, 
                    "Decryption Complete", 
                    "Do you want to open the decrypted file?",
                    QMessageBox.Yes | QMessageBox.No, 
                    QMessageBox.Yes
                )
                
                if reply == QMessageBox.Yes:
                    try:
                        import subprocess
                        if sys.platform == 'win32':
                            os.startfile(result)
                        elif sys.platform == 'darwin':
                            subprocess.call(['open', result])
                        else:
                            subprocess.call(['xdg-open', result])
                    except Exception as e:
                        print(f"Error opening file: {str(e)}")
                        QMessageBox.warning(self, "Error", f"Could not open file: {str(e)}")
            else:
                QMessageBox.warning(self, "Decryption Failed", result)
                self.statusBar().showMessage("Decryption failed", 5000)
        
        except Exception as e:
            print(f"Error processing decryption: {str(e)}")
            import traceback
            traceback.print_exc()
            QMessageBox.warning(self, "Error", f"Error during decryption: {str(e)}")
            self.statusBar().showMessage("Decryption failed", 5000)
    
    def manual_decrypt_file(self, encrypted_file_path, original_file_name):
        \"\"\"
        Handle manual decryption when automatic key exchange fails.
        
        Args:
            encrypted_file_path (str): Path to the encrypted file
            original_file_name (str): Original file name without .enc
        \"\"\"
        try:
            # Check if we have a decrypt_file method
            if not hasattr(self, 'decrypt_file'):
                QMessageBox.warning(self, "Error", "Decryption functionality not available")
                return
            
            # Ask user where to save the decrypted file
            save_dir = os.path.join(os.path.expanduser("~"), "Downloads")
            os.makedirs(save_dir, exist_ok=True)
            
            # Generate save path
            if original_file_name.endswith('.enc'):
                original_file_name = original_file_name[:-4]
                
            save_path, _ = QFileDialog.getSaveFileName(
                self, 
                "Save Decrypted File", 
                os.path.join(save_dir, original_file_name), 
                "All Files (*.*)"
            )
            
            if not save_path:
                self.statusBar().showMessage("Decryption cancelled", 3000)
                return
            
            # Show decryption status
            self.statusBar().showMessage("Decrypting file...", 3000)
            
            # Use the existing decrypt_file method
            success, result = self.decrypt_file(encrypted_file_path, save_path)
            
            if success:
                QMessageBox.information(self, "Decryption Complete", 
                                     f"File successfully decrypted and saved to:\n{result}")
                self.statusBar().showMessage(f"File decrypted and saved to: {result}", 5000)
                
                # Ask if user wants to open the file
                reply = QMessageBox.question(
                    self, 
                    "Decryption Complete", 
                    "Do you want to open the decrypted file?",
                    QMessageBox.Yes | QMessageBox.No, 
                    QMessageBox.Yes
                )
                
                if reply == QMessageBox.Yes:
                    try:
                        import subprocess
                        if sys.platform == 'win32':
                            os.startfile(result)
                        elif sys.platform == 'darwin':
                            subprocess.call(['open', result])
                        else:
                            subprocess.call(['xdg-open', result])
                    except Exception as e:
                        print(f"Error opening file: {str(e)}")
                        QMessageBox.warning(self, "Error", f"Could not open file: {str(e)}")
            else:
                QMessageBox.warning(self, "Decryption Failed", result)
                self.statusBar().showMessage("Decryption failed", 5000)
        
        except Exception as e:
            print(f"Error during manual decryption: {str(e)}")
            import traceback
            traceback.print_exc()
            QMessageBox.warning(self, "Error", f"Error during decryption: {str(e)}")
            self.statusBar().showMessage("Decryption failed", 5000)
    
    def ensure_keypair(self):
        \"\"\"
        Ensure that the user has a keypair, generating one if necessary.
        
        Returns:
            bool: True if keypair exists or was created, False otherwise
        \"\"\"
        try:
            # Check if keypair exists
            key_dir = os.path.join(os.path.expanduser("~"), ".decentrabrowser", "keys")
            os.makedirs(key_dir, exist_ok=True)
            
            private_key_path = os.path.join(key_dir, "private_key.pem")
            public_key_path = os.path.join(key_dir, "public_key.pem")
            
            if os.path.exists(private_key_path) and os.path.exists(public_key_path):
                return True
            
            # Generate a new keypair
            reply = QMessageBox.question(
                self, 
                "Key Generation", 
                "No encryption keys found. Do you want to generate a new keypair?",
                QMessageBox.Yes | QMessageBox.No, 
                QMessageBox.Yes
            )
            
            if reply == QMessageBox.Yes:
                # Generate RSA keypair
                from cryptography.hazmat.primitives.asymmetric import rsa
                from cryptography.hazmat.primitives import serialization
                
                private_key = rsa.generate_private_key(
                    public_exponent=65537,
                    key_size=2048
                )
                
                public_key = private_key.public_key()
                
                # Serialize private key
                pem_private = private_key.private_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PrivateFormat.PKCS8,
                    encryption_algorithm=serialization.NoEncryption()
                )
                
                # Serialize public key
                pem_public = public_key.public_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PublicFormat.SubjectPublicKeyInfo
                )
                
                # Save keys
                with open(private_key_path, 'wb') as f:
                    f.write(pem_private)
                
                with open(public_key_path, 'wb') as f:
                    f.write(pem_public)
                
                QMessageBox.information(self, "Key Generation", 
                                     "New keypair generated successfully.\n"
                                     f"Private key saved to: {private_key_path}\n"
                                     f"Public key saved to: {public_key_path}\n\n"
                                     "IMPORTANT: Keep your private key secure!")
                
                return True
            else:
                return False
        
        except Exception as e:
            print(f"Error ensuring keypair: {str(e)}")
            import traceback
            traceback.print_exc()
            QMessageBox.warning(self, "Error", f"Error generating keypair: {str(e)}")
            return False
    
    def load_public_key(self):
        \"\"\"
        Load the user's public key.
        
        Returns:
            str: PEM-encoded public key, or None if not available
        \"\"\"
        try:
            key_path = os.path.join(os.path.expanduser("~"), ".decentrabrowser", "keys", "public_key.pem")
            
            if not os.path.exists(key_path):
                return None
            
            with open(key_path, 'r') as f:
                public_key = f.read()
            
            return public_key
        
        except Exception as e:
            print(f"Error loading public key: {str(e)}")
            return None
    
    def decrypt_key(self, encrypted_key):
        \"\"\"
        Decrypt an encrypted key using the user's private key.
        
        Args:
            encrypted_key (str): Base64-encoded encrypted key
            
        Returns:
            str: Decrypted key, or None on error
        \"\"\"
        try:
            # Load private key
            from cryptography.hazmat.primitives.asymmetric import padding
            from cryptography.hazmat.primitives import hashes
            from cryptography.hazmat.primitives.asymmetric import rsa
            from cryptography.hazmat.primitives import serialization
            import base64
            
            key_path = os.path.join(os.path.expanduser("~"), ".decentrabrowser", "keys", "private_key.pem")
            
            if not os.path.exists(key_path):
                QMessageBox.warning(self, "Decryption Error", "Private key not found")
                return None
            
            with open(key_path, 'rb') as f:
                private_key = serialization.load_pem_private_key(
                    f.read(),
                    password=None
                )
            
            # Decode the encrypted key
            encrypted_data = base64.b64decode(encrypted_key)
            
            # Decrypt the key
            decrypted_key = private_key.decrypt(
                encrypted_data,
                padding.OAEP(
                    mgf=padding.MGF1(algorithm=hashes.SHA256()),
                    algorithm=hashes.SHA256(),
                    label=None
                )
            )
            
            return decrypted_key
        
        except Exception as e:
            print(f"Error decrypting key: {str(e)}")
            import traceback
            traceback.print_exc()
            return None
    
    def decrypt_file_with_key(self, encrypted_file_path, output_path, decryption_key):
        \"\"\"
        Decrypt a file using the provided decryption key.
        
        Args:
            encrypted_file_path (str): Path to the encrypted file
            output_path (str): Path to save the decrypted file
            decryption_key (bytes): The decryption key
            
        Returns:
            tuple: (success, result) where result is the output path or an error message
        \"\"\"
        try:
            from cryptography.fernet import Fernet
            
            # Read the encrypted data
            with open(encrypted_file_path, 'rb') as f:
                encrypted_data = f.read()
            
            # Create Fernet cipher with the key
            key_str = decryption_key
            if isinstance(key_str, bytes):
                # Convert to string if it's bytes
                try:
                    key_str = key_str.decode('utf-8')
                except:
                    # If not UTF-8, use base64 encoding
                    import base64
                    key_str = base64.b64encode(key_str).decode('utf-8')
            
            # Setup the cipher
            cipher = Fernet(key_str)
            
            # Decrypt the data
            decrypted_data = cipher.decrypt(encrypted_data)
            
            # Write the decrypted data
            with open(output_path, 'wb') as f:
                f.write(decrypted_data)
            
            return True, output_path
        
        except Exception as e:
            print(f"Error decrypting file: {str(e)}")
            import traceback
            traceback.print_exc()
            return False, f"Error: {str(e)}"
"""
    
    # Add import for QFileDialog if not present
    if 'QFileDialog' not in content:
        content = content.replace('from PyQt5.QtWidgets import', 'from PyQt5.QtWidgets import QFileDialog, ')
    
    # Add the methods to the MainWindow class
    updated_content = content[:class_end] + methods_to_add + content[class_end:]
    
    # Check if cryptography is imported, if not add it
    if 'from cryptography' not in updated_content:
        try_import = """
try:
    from cryptography.hazmat.primitives.asymmetric import rsa, padding
    from cryptography.hazmat.primitives import hashes, serialization
    from cryptography.fernet import Fernet
except ImportError:
    print("Warning: cryptography module not found. Enhanced encryption features will not work.")
    print("To install: pip install cryptography")
"""
        # Find the imports section (assuming it's at the top of the file)
        import_section_end = re.search(r'import.*?\n\n', updated_content, re.DOTALL)
        if import_section_end:
            position = import_section_end.end()
            updated_content = updated_content[:position] + try_import + updated_content[position:]
        else:
            # If we can't find a clear import section, add it after the module docstring
            docstring_match = re.search(r'""".*?"""', updated_content, re.DOTALL)
            if docstring_match:
                position = docstring_match.end() + 1
                updated_content = updated_content[:position] + try_import + "\n" + updated_content[position:]
            else:
                # Last resort, add at the top
                updated_content = try_import + "\n" + updated_content
    
    # Write the updated file
    backup_path = main_window_path + '.bak'
    with open(backup_path, 'w', encoding='utf-8') as f:
        f.write(content)
    print(f"Backed up original file to {backup_path}")
    
    with open(main_window_path, 'w', encoding='utf-8') as f:
        f.write(updated_content)
    
    print("Added enhanced download methods to MainWindow class!")
    return True

def add_key_handler_to_http_server():
    """Add key request handler to HTTP server."""
    
    # Find HTTP server file
    http_server_found = False
    for root, _, files in os.walk(os.path.join(os.getcwd(), "decentrabrowser")):
        for file in files:
            if file.endswith('.py') and ('http' in file.lower() or 'server' in file.lower()):
                http_server_path = os.path.join(root, file)
                
                # Check if this file has HTTP server functionality
                with open(http_server_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                    if 'class' in content and ('HTTP' in content or 'BaseHTTPRequestHandler' in content):
                        http_server_found = True
                        break
        if http_server_found:
            break
    
    if not http_server_found:
        print("Could not find HTTP server file")
        return False
    
    print(f"Found HTTP server at: {http_server_path}")
    
    # Read the file
    with open(http_server_path, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Check if key handler already exists
    if 'def handle_key_request' in content:
        print("Key handler already exists in HTTP server")
        return True
    
    # Find the request handler class
    handler_match = re.search(r'class\s+\w+\s*\(\s*(?:BaseHTTPRequestHandler|HTTPRequestHandler|SimpleHTTPRequestHandler)\s*\):(.*?)(?=\n\S)', content, re.DOTALL)
    if not handler_match:
        print("Could not find HTTP request handler class")
        return False
    
    handler_end = handler_match.end()
    
    # Create methods to add
    methods_to_add = """
    def handle_key_request(self):
        \"\"\"Handle encryption key requests with secure key exchange.\"\"\"
        try:
            # Read request data
            content_length = int(self.headers.get('Content-Length', 0))
            if content_length == 0:
                self.send_error(400, "No request data")
                return
            
            post_data = self.rfile.read(content_length)
            
            import json
            data = json.loads(post_data)
            
            # Get the requester's public key
            public_key_str = data.get('public_key')
            if not public_key_str:
                self.send_error(400, "No public key provided")
                return
            
            # Get the requested file name from URL
            file_name = self.path[5:]  # Remove '/key/' prefix
            
            # Generate or retrieve the encryption key for this file
            file_key = self.get_file_encryption_key(file_name)
            if not file_key:
                self.send_error(404, "Key not found")
                return
            
            # Encrypt the file key with the requester's public key
            encrypted_key = self.encrypt_with_public_key(file_key, public_key_str)
            
            # Send the encrypted key
            response = {'encrypted_key': encrypted_key}
            
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            
            self.wfile.write(json.dumps(response).encode('utf-8'))
        
        except Exception as e:
            print(f"Error handling key request: {str(e)}")
            import traceback
            traceback.print_exc()
            self.send_error(500, f"Internal Server Error: {str(e)}")

    def get_file_encryption_key(self, file_name):
        \"\"\"
        Get the encryption key for a file.
        
        Args:
            file_name (str): Name of the file
            
        Returns:
            str: Base64-encoded encryption key or None if not found
        \"\"\"
        try:
            # Check if key exists in keys directory
            key_dir = os.path.join(os.path.expanduser("~"), ".decentrabrowser", "file_keys")
            os.makedirs(key_dir, exist_ok=True)
            
            key_path = os.path.join(key_dir, f"{file_name}.key")
            
            if os.path.exists(key_path):
                with open(key_path, 'r') as f:
                    return f.read().strip()
            
            # If not found, check if we have a master key
            master_key_path = os.path.join(key_dir, "master_key")
            if os.path.exists(master_key_path):
                with open(master_key_path, 'r') as f:
                    return f.read().strip()
            
            # Generate a new key if not found
            from cryptography.fernet import Fernet
            new_key = Fernet.generate_key().decode('utf-8')
            
            # Save the key for future use
            with open(key_path, 'w') as f:
                f.write(new_key)
            
            return new_key
        
        except Exception as e:
            print(f"Error getting file key: {str(e)}")
            return None

    def encrypt_with_public_key(self, file_key, public_key_str):
        \"\"\"
        Encrypt a file key with the user's public key.
        
        Args:
            file_key (str): The file encryption key
            public_key_str (str): Base64-encoded public key
            
        Returns:
            str: Base64-encoded encrypted key
        \"\"\"
        try:
            from cryptography.hazmat.primitives.asymmetric import padding
            from cryptography.hazmat.primitives import hashes
            from cryptography.hazmat.primitives import serialization
            import base64
            
            # Decode the public key string
            public_key_data = base64.b64decode(public_key_str)
            
            # Load the public key
            public_key = serialization.load_pem_public_key(public_key_data)
            
            # Encrypt the file key
            encrypted_key = public_key.encrypt(
                file_key.encode('utf-8'),
                padding.OAEP(
                    mgf=padding.MGF1(algorithm=hashes.SHA256()),
                    algorithm=hashes.SHA256(),
                    label=None
                )
            )
            
            # Encode the encrypted key to base64
            return base64.b64encode(encrypted_key).decode('utf-8')
        
        except Exception as e:
            print(f"Error encrypting with public key: {str(e)}")
            import traceback
            traceback.print_exc()
            return None
"""
    
    # Update do_GET method to handle key requests
    do_get_match = re.search(r'def\s+do_GET\s*\([^)]*\):(.*?)(?=def|\Z)', content, re.DOTALL)
    if do_get_match:
        do_get_code = do_get_match.group(0)
        
        # Check if do_GET already handles key requests
        if '/key/' in do_get_code:
            print("do_GET already handles key requests")
        else:
            # Add key request handling to do_GET
            key_handling = """
            elif path.startswith('/key/'):
                self.handle_key_request()"""
            
            # Look for the last elif or if in do_GET
            last_if_match = re.search(r'(?:elif|if|else)[^:]*:', do_get_code)
            if last_if_match:
                # Find the end of the last if/elif/else block
                last_if_pos = do_get_code.rfind(':', last_if_match.start())
                # Insert our key handling after it
                updated_do_get = do_get_code[:last_if_pos+1] + key_handling + do_get_code[last_if_pos+1:]
                # Update the content
                content = content.replace(do_get_code, updated_do_get)
    
    # Add the methods to the handler class
    updated_content = content[:handler_end] + methods_to_add + content[handler_end:]
    
    # Check if cryptography is imported, if not add it
    if 'from cryptography' not in updated_content:
        try_import = """
try:
    from cryptography.hazmat.primitives.asymmetric import rsa, padding
    from cryptography.hazmat.primitives import hashes, serialization
    from cryptography.fernet import Fernet
except ImportError:
    print("Warning: cryptography module not found. Enhanced encryption features will not work.")
    print("To install: pip install cryptography")
"""
        # Find the imports section (assuming it's at the top of the file)
        import_section_end = re.search(r'import.*?\n\n', updated_content, re.DOTALL)
        if import_section_end:
            position = import_section_end.end()
            updated_content = updated_content[:position] + try_import + updated_content[position:]
        else:
            # If we can't find a clear import section, add it after the module docstring
            docstring_match = re.search(r'""".*?"""', updated_content, re.DOTALL)
            if docstring_match:
                position = docstring_match.end() + 1
                updated_content = updated_content[:position] + try_import + "\n" + updated_content[position:]
            else:
                # Last resort, add at the top
                updated_content = try_import + "\n" + updated_content
    
    # Write the updated file
    backup_path = http_server_path + '.bak'
    with open(backup_path, 'w', encoding='utf-8') as f:
        f.write(content)
    print(f"Backed up original file to {backup_path}")
    
    with open(http_server_path, 'w', encoding='utf-8') as f:
        f.write(updated_content)
    
    print("Added key request handler to HTTP server!")
    return True

if __name__ == "__main__":
    print("DecentraBrowser Enhanced Download Feature Installer")
    print("=================================================")
    
    print("\nAdding enhanced download methods to MainWindow...")
    if add_methods_to_main_window():
        print("Successfully added enhanced download methods to MainWindow!")
    else:
        print("Failed to add methods to MainWindow")
    
    print("\nAdding key handler to HTTP server...")
    if add_key_handler_to_http_server():
        print("Successfully added key handler to HTTP server!")
    else:
        print("Failed to add key handler to HTTP server")
    
    print("\nInstallation complete! Please install the required dependencies:")
    print("  pip install cryptography requests")
    print("\nRestart your application for the changes to take effect.")