File size: 2,086 Bytes
d44fddd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
use tauri::{AppHandle, Manager};
use crate::adblock::engine::AdBlockState;

/// Resolve user input to a navigable URL with HTTPS-first.
pub fn resolve_url(input: &str) -> String {
    let trimmed = input.trim();
    if trimmed.is_empty() { return "https://duckduckgo.com".to_string(); }
    let lower = trimmed.to_ascii_lowercase();
    if lower.starts_with("javascript:") || lower.starts_with("data:") || lower.starts_with("file:") || lower.starts_with("tauri:") || lower.starts_with("asset:") {
        return format!("https://duckduckgo.com/?q={}", urlencoded(trimmed));
    }
    if trimmed.starts_with("http://") || trimmed.starts_with("https://") {
        if trimmed.starts_with("http://") {
            let host = trimmed.split("//").nth(1).and_then(|s| s.split('/').next()).unwrap_or("");
            if host != "localhost" && host != "127.0.0.1" && host != "::1" {
                return trimmed.replacen("http://", "https://", 1);
            }
        }
        return trimmed.to_string();
    }
    if trimmed.contains('.') && !trimmed.contains(' ') {
        return format!("https://{trimmed}");
    }
    format!("https://duckduckgo.com/?q={}", urlencoded(trimmed))
}

/// Check if a URL should be blocked by security policy or adblock at navigation level.
pub fn navigation_blocked(app: &AppHandle, url: &str) -> bool {
    let lower = url.trim().to_ascii_lowercase();
    if lower.starts_with("javascript:") || lower.starts_with("data:") || lower.starts_with("file:") || lower.starts_with("tauri:") || lower.starts_with("asset:") {
        return true;
    }
    if !(lower.starts_with("http://") || lower.starts_with("https://") || lower.starts_with("lumaref-action://")) {
        return true;
    }
    let state = app.state::<AdBlockState>();
    state.should_block(url, url, "document")
}

fn urlencoded(value: &str) -> String {
    value.bytes().flat_map(|b| match b {
        b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => vec![b as char],
        b' ' => vec!['+'],
        _ => format!("%{b:02X}").chars().collect(),
    }).collect()
}