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()
}
|