cttps 0.1.2

Crypto Transfer Protocol Secure (CTTPS) - A high-performance secure transport protocol using X25519 and AES-256-GCM.
use cttps::CttpsStream;
use eframe::egui;
use tokio::net::TcpStream;
use std::sync::mpsc::{self, Receiver, Sender};
use tokio::runtime::Runtime;

struct CttpsBrowser {
    url: String,
    content: String,
    logs: Vec<String>,
    is_loading: bool,
    runtime: Runtime,
    log_tx: Sender<String>,
    log_rx: Receiver<String>,
    content_rx: Option<Receiver<String>>,
    bridge_content: Vec<(String, String)>, // (URL, Content)
    bridge_receivers: Vec<Receiver<(String, String)>>,
}

impl CttpsBrowser {
    fn new(cc: &eframe::CreationContext<'_>) -> Self {
        cc.egui_ctx.set_visuals(egui::Visuals::dark());
        
        let (log_tx, log_rx) = mpsc::channel();
        
        Self {
            url: "cttps://127.0.0.1:8080/".to_string(),
            content: "Welcome to CTTPS Browser. Enter a URL to start securely browsing.".to_string(),
            logs: vec!["Browser initialized.".to_string()],
            is_loading: false,
            runtime: Runtime::new().unwrap(),
            log_tx,
            log_rx,
            content_rx: None,
            bridge_content: Vec::new(),
            bridge_receivers: Vec::new(),
        }
    }

    fn fetch_url(&mut self) {
        let url = self.url.clone();
        let log_tx = self.log_tx.clone();
        let (content_tx, content_rx) = mpsc::channel();
        self.content_rx = Some(content_rx);
        self.is_loading = true;
        self.bridge_content.clear();
        self.bridge_receivers.clear();
        
        self.runtime.spawn(async move {
            let _ = log_tx.send(format!("Parsing URL: {}", url));
            let addr = url.trim_start_matches("cttps://").split('/').next().unwrap_or("127.0.0.1:8080");
            
            let _ = log_tx.send(format!("Connecting to {}...", addr));
            match tokio::time::timeout(std::time::Duration::from_secs(5), TcpStream::connect(addr)).await {
                Ok(Ok(stream)) => {
                    let _ = log_tx.send("TCP Connected. Starting Handshake...".to_string());
                    match tokio::time::timeout(std::time::Duration::from_secs(5), CttpsStream::connect(stream)).await {
                        Ok(Ok(mut cttps)) => {
                            let _ = log_tx.send("CTTPS Handshake Success!".to_string());
                            let request = "GET / HTTP/1.1\r\n\r\n";
                            if let Err(e) = cttps.write_packet(request.as_bytes()).await {
                                let _ = log_tx.send(format!("Write Error: {}", e));
                                return;
                            }
                            
                            let _ = log_tx.send("Request sent. Reading response...".to_string());
                            match tokio::time::timeout(std::time::Duration::from_secs(5), cttps.read_packet()).await {
                                Ok(Ok(data)) => {
                                    let _ = log_tx.send(format!("Response received ({} bytes).", data.len()));
                                    let response_text = String::from_utf8_lossy(&data).to_string();
                                    let _ = content_tx.send(response_text);
                                }
                                Ok(Err(e)) => { 
                                    let _ = log_tx.send(format!("Protocol Error: {}", e));
                                    let _ = content_tx.send(format!("Error: {}", e));
                                }
                                Err(_) => { 
                                    let _ = log_tx.send("Read Timeout".to_string());
                                    let _ = content_tx.send("Error: Read Timeout".to_string());
                                }
                            }
                        }
                        Ok(Err(e)) => { 
                            let _ = log_tx.send(format!("Handshake Error: {}", e));
                            let _ = content_tx.send(format!("Handshake Error: {}", e));
                        }
                        Err(_) => { 
                            let _ = log_tx.send("Handshake Timeout".to_string());
                            let _ = content_tx.send("Handshake Timeout".to_string());
                        }
                    }
                }
                Ok(Err(e)) => { 
                    let _ = log_tx.send(format!("Connection Failed: {}", e));
                    let _ = content_tx.send(format!("Connection Failed: {}", e));
                }
                Err(_) => { 
                    let _ = log_tx.send("Connection Timeout".to_string());
                    let _ = content_tx.send("Connection Timeout".to_string());
                }
            }
        });
    }

    fn check_for_bridge(&mut self) {
        let content = self.content.clone();
        let start_tag = "<https>";
        let end_tag = "</https>";
        
        let mut search_pos = 0;
        while let Some(start_idx) = content[search_pos..].find(start_tag) {
            let actual_start = search_pos + start_idx + start_tag.len();
            if let Some(end_idx) = content[actual_start..].find(end_tag) {
                let actual_end = actual_start + end_idx;
                let https_url = content[actual_start..actual_end].to_string();
                
                if !self.bridge_content.iter().any(|(u, _)| u == &https_url) {
                    self.fetch_bridge_url(https_url);
                }
                search_pos = actual_end + end_tag.len();
            } else {
                break;
            }
        }
    }

    fn fetch_bridge_url(&mut self, url: String) {
        let log_tx = self.log_tx.clone();
        let (tx, rx) = mpsc::channel();
        let url_clone = url.clone();
        
        self.runtime.spawn(async move {
            let _ = log_tx.send(format!("Bridge: Fetching HTTPS content from {}...", url_clone));
            match reqwest::get(&url_clone).await {
                Ok(resp) => {
                    match resp.text().await {
                        Ok(text) => {
                            let _ = log_tx.send(format!("Bridge: Received {} bytes from HTTPS.", text.len()));
                            let _ = tx.send((url_clone, text));
                        }
                        Err(e) => { let _ = log_tx.send(format!("Bridge Error: {}", e)); }
                    }
                }
                Err(e) => { let _ = log_tx.send(format!("Bridge Network Error: {}", e)); }
            }
        });

        self.bridge_receivers.push(rx);
    }
}

impl eframe::App for CttpsBrowser {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        while let Ok(log) = self.log_rx.try_recv() {
            self.logs.push(log);
        }
        
        if self.is_loading {
            if let Some(rx) = &self.content_rx {
                match rx.try_recv() {
                    Ok(content) => {
                        self.content = content;
                        self.is_loading = false;
                        self.logs.push("Page loaded successfully.".to_string());
                        self.check_for_bridge();
                    }
                    Err(mpsc::TryRecvError::Empty) => {}
                    Err(mpsc::TryRecvError::Disconnected) => {
                        self.is_loading = false;
                        self.logs.push("Error: Background task disconnected.".to_string());
                        self.content_rx = None;
                    }
                }
            }
        }

        // Poll bridge receivers
        let mut i = 0;
        while i < self.bridge_receivers.len() {
            match self.bridge_receivers[i].try_recv() {
                Ok(data) => {
                    self.bridge_content.push(data);
                    self.bridge_receivers.remove(i);
                }
                Err(mpsc::TryRecvError::Empty) => {
                    i += 1;
                }
                Err(mpsc::TryRecvError::Disconnected) => {
                    self.bridge_receivers.remove(i);
                }
            }
        }

        egui::CentralPanel::default().show(ctx, |ui| {
            ui.vertical_centered(|ui| {
                ui.heading("🔒 CTTPS Secure Web Browser");
                ui.add_space(5.0);
            });

            ui.horizontal(|ui| {
                ui.label("URL:");
                let edit = ui.add(egui::TextEdit::singleline(&mut self.url).desired_width(f32::INFINITY));
                
                let enter_pressed = edit.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter));
                
                if ui.button("Navigate").clicked() || enter_pressed {
                    self.logs.push(format!("Initiating request to: {}", self.url));
                    self.fetch_url();
                }
            });

            ui.add_space(10.0);
            ui.separator();

            ui.columns(2, |columns| {
                columns[0].vertical(|ui| {
                    ui.label(egui::RichText::new("Decrypted Page (HTML)").strong());
                    egui::ScrollArea::vertical().id_source("page").show(ui, |ui| {
                        ui.add(egui::TextEdit::multiline(&mut self.content).desired_width(f32::INFINITY).desired_rows(12));
                        
                        if !self.bridge_content.is_empty() {
                            ui.add_space(20.0);
                            ui.label(egui::RichText::new("--- HTTPS Bridge Content ---").color(egui::Color32::from_rgb(255, 215, 0)));
                            for (url, content) in &self.bridge_content {
                                ui.group(|ui| {
                                    ui.label(egui::RichText::new(format!("Source: {}", url)).italics().size(9.0).color(egui::Color32::LIGHT_BLUE));
                                    ui.label(content);
                                });
                            }
                        }
                    });
                });

                columns[1].vertical(|ui| {
                    ui.label(egui::RichText::new("Security & Handshake Logs").strong().color(egui::Color32::GREEN));
                    egui::ScrollArea::vertical().id_source("logs").stick_to_bottom(true).show(ui, |ui| {
                        for log in &self.logs {
                            ui.label(egui::RichText::new(format!("> {}", log)).size(10.0).color(egui::Color32::LIGHT_GRAY));
                        }
                    });
                });
            });
        });

        ctx.request_repaint();
    }
}

fn main() -> Result<(), eframe::Error> {
    let options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default().with_inner_size([1100.0, 700.0]),
        ..Default::default()
    };
    eframe::run_native(
        "CTTPS Secure Browser",
        options,
        Box::new(|cc| Box::new(CttpsBrowser::new(cc))),
    )
}