//! Basic SSRF-minded URL checks for screenshot targets.

use anyhow::{anyhow, Result};
use std::net::IpAddr;
use url::Url;

fn is_private_or_loopback_ip(ip: IpAddr) -> bool {
    match ip {
        IpAddr::V4(v4) => v4.is_private() || v4.is_loopback() || v4.is_link_local(),
        IpAddr::V6(v6) => v6.is_loopback() || v6.is_unique_local(),
    }
}

/// Allow `http` and `https` only; block obvious local/private targets.
pub fn assert_url_allowed(url_str: &str) -> Result<Url> {
    let u = Url::parse(url_str).map_err(|e| anyhow!("invalid URL: {}", e))?;
    match u.scheme() {
        "http" | "https" => {}
        other => return Err(anyhow!("scheme not allowed: {}", other)),
    }
    let host = u.host_str().ok_or_else(|| anyhow!("URL missing host"))?;
    let host_lc = host.to_lowercase();
    if host_lc == "localhost" || host_lc.ends_with(".localhost") {
        return Err(anyhow!("host not allowed"));
    }
    if let Ok(ip) = host.parse::<IpAddr>() {
        if is_private_or_loopback_ip(ip) {
            return Err(anyhow!("IP not allowed"));
        }
    }
    if host == "0.0.0.0" {
        return Err(anyhow!("IP not allowed"));
    }
    Ok(u)
}
