Deployment script for the DecentraBrowser system.
"""
import os
import sys
import argparse
import subprocess
import platform
import shutil
import zipfile
from pathlib import Path

def build_package():
    """Build package for deployment."""
    print("Building package...")
    
    # Clean build directory
    if os.path.exists("build"):
        shutil.rmtree("build")
    
    if os.path.exists("dist"):
        shutil.rmtree("dist")
    
    # Create setup.py for building
    setup_py = """
from setuptools import setup, find_packages

setup(
    name="decentrabrowser",
    version="0.1.0",
    packages=find_packages(),
    install_requires=[
        "cryptography>=3.4.0",
        "PyQt5>=5.15.4",
        "flask>=2.0.1",
        "requests>=2.25.1",
        "pyOpenSSL>=20.0.1",
        "pycryptodome>=3.10.1",
        "click>=8.0.0",
        "python-dotenv>=0.19.0",
        "tinydb>=4.5.0",
        "marshmallow>=3.13.0",
        "aiohttp>=3.7.4",
        "sqlalchemy>=1.4.23",
        "pynacl>=1.4.0",
        "qrcode>=7.3.1",
        "pillow>=8.3.1",
        "PyQtWebEngine>=5.15.4",
        "colorama>=0.4.4",
    ],
    entry_points={
        "console_scripts": [
            "decentrabrowser-client=decentrabrowser.client.app:main",
            "decentrabrowser-server=decentrabrowser.central_server.app:main",
        ],
    },
)
"""
    
    with open("setup.py", "w") as f:
        f.write(setup_py)
    
    # Build package
    subprocess.check_call([sys.executable, "setup.py", "sdist", "bdist_wheel"])
    
    print("Package built successfully")

def build_executable():
    """Build executable for deployment."""
    print("Building executable...")
    
    # Check PyInstaller installation
    try:
        import PyInstaller
    except ImportError:
        print("Installing PyInstaller...")
        subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
    
    # Determine spec file
    if platform.system() == "Windows":
        icon_option = "--icon=resources/icon.ico"
    elif platform.system() == "Darwin":
        icon_option = "--icon=resources/icon.icns"
    else:
        icon_option = "--icon=resources/icon.png"
    
    # Build client executable
    print("Building client executable...")
    subprocess.check_call([
        "pyinstaller",
        "--name=DecentraBrowser",
        "--onefile",
        icon_option,
        "--windowed",
        "--add-data=resources;resources",
        "decentrabrowser/client/app.py"
    ])
    
    # Build server executable
    print("Building server executable...")
    subprocess.check_call([
        "pyinstaller",
        "--name=DecentraBrowserServer",
        "--onefile",
        icon_option,
        "decentrabrowser/central_server/app.py"
    ])
    
    print("Executables built successfully")

def create_installer():
    """Create installer for deployment."""
    print("Creating installer...")
    
    if platform.system() == "Windows":
        # Create Inno Setup script
        iss_script = """
        [Setup]
        AppName=DecentraBrowser
        AppVersion=0.1.0
        DefaultDirName={autopf}\\DecentraBrowser
        DefaultGroupName=DecentraBrowser
        UninstallDisplayIcon={app}\\DecentraBrowser.exe
        Compression=lzma2
        SolidCompression=yes
        OutputDir=installer
        OutputBaseFilename=DecentraBrowser_Setup
        
        [Files]
        Source: "dist\\DecentraBrowser.exe"; DestDir: "{app}"; Flags: ignoreversion
        Source: "dist\\DecentraBrowserServer.exe"; DestDir: "{app}"; Flags: ignoreversion
        Source: "resources\\*"; DestDir: "{app}\\resources"; Flags: ignoreversion recursesubdirs
        
        [Icons]
        Name: "{group}\\DecentraBrowser"; Filename: "{app}\\DecentraBrowser.exe"
        Name: "{group}\\DecentraBrowser Server"; Filename: "{app}\\DecentraBrowserServer.exe"
        Name: "{commondesktop}\\DecentraBrowser"; Filename: "{app}\\DecentraBrowser.exe"
        """
        
        os.makedirs("installer", exist_ok=True)
        
        with open("installer.iss", "w") as f:
            f.write(iss_script)
        
        # Run Inno Setup Compiler
        subprocess.check_call(["iscc", "installer.iss"])
        
    elif platform.system() == "Darwin":
        # Create macOS DMG
        subprocess.check_call([
            "hdiutil",
            "create",
            "-volname",
            "DecentraBrowser",
            "-srcfolder",
            "dist/DecentraBrowser.app",
            "-ov",
            "-format",
            "UDZO",
            "installer/DecentraBrowser.dmg"
        ])
        
    else:
        # Create Linux installer using fpm
        try:
            subprocess.check_call(["fpm", "--version"])
        except (subprocess.CalledProcessError, FileNotFoundError):
            print("fpm not found. Please install fpm to create Linux packages.")
            print("See: https://fpm.readthedocs.io/en/latest/installation.html")
            return
        
        # Create deb package
        subprocess.check_call([
            "fpm",
            "-s", "dir",
            "-t", "deb",
            "-n", "decentrabrowser",
            "-v", "0.1.0",
            "--prefix=/usr/local",
            "dist/DecentraBrowser=/usr/local/bin/",
            "dist/DecentraBrowserServer=/usr/local/bin/",
            "resources/=/usr/local/share/decentrabrowser/resources/"
        ])
        
        # Create rpm package
        subprocess.check_call([
            "fpm",
            "-s", "dir",
            "-t", "rpm",
            "-n", "decentrabrowser",
            "-v", "0.1.0",
            "--prefix=/usr/local",
            "dist/DecentraBrowser=/usr/local/bin/",
            "dist/DecentraBrowserServer=/usr/local/bin/",
            "resources/=/usr/local/share/decentrabrowser/resources/"
        ])
    
    print("Installer created successfully")

def create_zip_package():
    """Create ZIP package for deployment."""
    print("Creating ZIP package...")
    
    # Create dist directory if it doesn't exist
    os.makedirs("dist", exist_ok=True)
    
    # Determine ZIP filename
    if platform.system() == "Windows":
        zip_filename = "dist/DecentraBrowser_Windows.zip"
    elif platform.system() == "Darwin":
        zip_filename = "dist/DecentraBrowser_macOS.zip"
    else:
        zip_filename = "dist/DecentraBrowser_Linux.zip"
    
    # Create ZIP file
    with zipfile.ZipFile(zip_filename, "w", zipfile.ZIP_DEFLATED) as zipf:
        # Add executables
        if platform.system() == "Windows":
            zipf.write("dist/DecentraBrowser.exe", "DecentraBrowser.exe")
            zipf.write("dist/DecentraBrowserServer.exe", "DecentraBrowserServer.exe")
        else:
            zipf.write("dist/DecentraBrowser", "DecentraBrowser")
            zipf.write("dist/DecentraBrowserServer", "DecentraBrowserServer")
        
        # Add resources
        for root, dirs, files in os.walk("resources"):
            for file in files:
                file_path = os.path.join(root, file)
                zipf.write(file_path, os.path.relpath(file_path, "resources"))
        
        # Add README and LICENSE
        if os.path.exists("README.md"):
            zipf.write("README.md")
        if os.path.exists("LICENSE"):
            zipf.write("LICENSE")
    
    print(f"ZIP package created at {zip_filename}")

def main():
    """Main deployment function."""
    parser = argparse.ArgumentParser(description="DecentraBrowser Deployment Script")
    parser.add_argument("--package", action="store_true",
                        help="Build Python package")
    parser.add_argument("--exe", action="store_true",
                        help="Build executable")
    parser.add_argument("--installer", action="store_true",
                        help="Create installer")
    parser.add_argument("--zip", action="store_true",
                        help="Create ZIP package")
    parser.add_argument("--all", action="store_true",
                        help="Build all deployment artifacts")
    
    args = parser.parse_args()
    
    print("DecentraBrowser Deployment")
    print("=========================")
    
    # Default to building package if no options specified
    if not (args.package or args.exe or args.installer or args.zip or args.all):
        args.package = True
    
    # Build all if --all specified
    if args.all:
        args.package = True
        args.exe = True
        args.installer = True
        args.zip = True
    
    # Build package
    if args.package:
        build_package()
    
    # Build executable
    if args.exe:
        build_executable()
    
    # Create installer
    if args.installer:
        create_installer()
    
    # Create ZIP package
    if args.zip:
        create_zip_package()
    
    print("\nDeployment Complete!")

if __name__ == "__main__":
    main()

#####################################################################
# README.md
#####################################################################

"""
# DecentraBrowser

A decentralized browser system with custom DDNS, encryption, and P2P communication features.

## Overview

DecentraBrowser is a Python-based implementation of a decentralized browsing system that enables:

- Custom domain naming with format `prefix.main.suffix.domain`
- Perfect Forward Secrecy (PFS) for secure communications
- RSA and AES encryption for secure data transfer
- P2P messaging between domain owners and users
- Ephemeral domains that exist only while servers are active

## Installation

### Prerequisites

- Python 3.8 or higher
- PyQt5 for the GUI
- Flask for the central server
- Cryptography libraries for security features

### Quick Installation

```bash
# Clone the repository
git clone https://github.com/yourusername/decentrabrowser.git
cd decentrabrowser

# Run the installation script
python decentrabrowser/scripts/install.py
```

### Manual Installation

```bash
# Install dependencies
pip install -r requirements.txt

# Run the client
python -m decentrabrowser.client.app

# Run the central server (separate terminal)
python -m decentrabrowser.central_server.app
```

## Usage

### Client

The client application provides a GUI for browsing and connecting to domains, downloading files, and sending P2P messages.

- **Domains Tab**: Browse available domains and connect to them
- **Files Tab**: View and download files from connected domains
- **Command Tab**: Interact with the system using command-line interface
- **Certificates Tab**: Manage encryption certificates

### Command Line Interface

The client supports the following commands:

- `/sources`: List all available domains
- `/download filename domainname [save_dir]`: Download a file from a domain
- `/p2p domainname timer message`: Send a P2P message to a domain

### Creating a Domain

1. Click "Create Domain" in the toolbar
2. Enter domain name parts (prefix, main, suffix)
3. Set a title and port
4. Click "Create Domain" to register with the central server

## Architecture

DecentraBrowser consists of three main components:

1. **Central Server**: Manages domain registration and discovery
2. **Client Browser**: Connects to domains and displays content
3. **Domain Server**: Serves content from a local directory

### Security Features

- **RSA Key Pairs**: Used for authentication and key exchange
- **AES Encryption**: Used for efficient encryption of data
- **PFS Sessions**: Ensure future key compromise doesn't affect current communications
- **Certificate Management**: Verifies domain ownership and authenticity

## Development

### Project Structure

```
/decentrabrowser/
  ├── central_server/      # Central registration server
  ├── client/              # Client browser application
  │   ├── gui/             # GUI components
  │   ├── network/         # Network utilities
  │   └── security/        # Security and encryption
  ├── shared/              # Shared utilities and protocols
  ├── docs/                # Documentation
  └── tests/               # Test suite
```

### Running Tests

```bash
# Run all tests
python -m unittest discover

# Run specific test module
python -m unittest decentrabrowser.tests.test_security
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

This project is licensed under the MIT License - see the LICENSE file for details.
"""

#####################################################################
# Example Domain Setup
#####################################################################

"""
# Example of registering and setting up a domain

from decentrabrowser.shared.utils import get_local_ip, setup_logging, ensure_directory_exists
from decentrabrowser.shared.security import SecurityManager
from decentrabrowser.shared.domain import Domain
from decentrabrowser.client.network.http_server import DomainServer
from decentrabrowser.client.network.client import NetworkClient
from decentrabrowser.shared.ddns import DDNS
import os

# Setup logging
logger = setup_logging('example_setup')

# Setup directories
data_dir = "decentrabrowser_data"
ensure_directory_exists(data_dir)
certs_dir = ensure_directory_exists(os.path.join(data_dir, 'certs'))
content_dir = ensure_directory_exists(os.path.join(data_dir, 'content'))

# Setup security manager
security_manager = SecurityManager(certs_dir)

# Create RSA key pair if not exists
if not os.path.exists(os.path.join(certs_dir, 'private_key.pem')):
    private_key, public_key = security_manager.generate_rsa_keypair()
    security_manager.save_private_key(private_key, 'private_key.pem')
    security_manager.save_public_key(public_key, 'public_key.pem')
    logger.info("Generated new RSA key pair")

# Setup DDNS
ddns_file = os.path.join(data_dir, 'ddns.json')
ddns = DDNS(ddns_file)

# Create network client
network_client = NetworkClient(security_manager, ddns, 'localhost', 8800)

# Create domain
domain = Domain(
    prefix='example',
    main='test',
    suffix='net',
    ip=get_local_ip(),
    port=8844
)
domain.title = "Example Test Domain"

# Register domain
success, message = network_client.register_domain(domain)
if success:
    logger.info(f"Domain registered: {domain.full_name}")
    
    # Add to DDNS
    ddns.add_entry(domain.full_name, domain.ip, domain.port)
    
    # Create domain server
    domain_server = DomainServer(domain, security_manager, content_dir, port=domain.port)
    
    # Start domain server
    if domain_server.start():
        logger.info(f"Domain server started on port {domain.port}")
        
        # Keep server running
        try:
            input("Press Enter to stop the server...")
        except KeyboardInterrupt:
            pass
        finally:
            # Stop server and unregister domain
            domain_server.stop()
            network_client.unregister_domain(domain.full_name)
            logger.info("Domain server stopped and domain unregistered")
    else:
        logger.error("Failed to start domain server")
else:
    logger.error(f"Failed to register domain: {message}")