#!/usr/bin/env python3
"""Shared SSRF guard for outbound image/file fetches (issue #210).

Canvas page HTML can embed an <img src="..."> pointing anywhere — including
loopback, RFC1918, or link-local (cloud metadata) hosts. is_safe_fetch_url()
resolves the host and rejects anything that isn't a public http(s) address
before a fetch is attempted. MAX_FETCH_BYTES caps how much of a response
callers should buffer/write once a fetch is allowed to proceed.
"""

import ipaddress
import socket
from urllib.parse import urlparse

MAX_FETCH_BYTES = 25 * 1024 * 1024  # 25 MB — sane cap for an audited image/file


def is_safe_fetch_url(url):
    """Return True if url is safe to fetch: http(s) scheme, and every address
    the host resolves to is public (not private/loopback/link-local/reserved).

    Checks the resolved IP(s), not just the literal — a hostname can resolve
    to a private address even when it doesn't look like one.
    """
    parsed = urlparse(url or "")
    if parsed.scheme.lower() not in ("http", "https"):
        return False
    host = parsed.hostname
    if not host:
        return False
    try:
        addrinfo = socket.getaddrinfo(host, None)
    except socket.gaierror:
        return False
    for family, _type, _proto, _canonname, sockaddr in addrinfo:
        try:
            ip = ipaddress.ip_address(sockaddr[0])
        except ValueError:
            return False
        if (
            ip.is_private
            or ip.is_loopback
            or ip.is_link_local
            or ip.is_reserved
            or ip.is_multicast
            or ip.is_unspecified
        ):
            return False
    return True
