Downloads a user-supplied URL to a temporary file without letting it reach the server's own network.
A URL is a request for the server to connect somewhere, and the
"somewhere" is the attacker's to choose: http://169.254.169.254/ (cloud
credentials), http://localhost:5432/, a name that resolves to an internal
address, or one that resolves to a public address when checked and an
internal one a moment later (DNS rebinding). So:
- only
httpsby default (allow_http: trueto allow plain http), no credentials in the URL, ports 80/443 unlessallowed_ports:says so; - the host is resolved once, every address it resolves to must be
public (
PhoenixKit.Utils.PublicAddress), and the connection is made to the address that was checked — with the original name forHost, SNI and certificate verification (Mint's:hostname), so nothing resolves the name again between the check and the connect; - redirects are followed by hand (at most
max_redirects, default 3), each hop checked again, and an https URL never redirects to http; - the body is streamed to a temporary file and cut off at
max_bytes(default 25 MB) whateverContent-Lengthclaims, within one overalltimeout(default 15 s).
download/2 returns {:ok, %{path: temp_path, filename: name, url: final_url}};
the caller removes the temporary file. What the bytes ARE is decided later,
by sniffing them (Storage.store_from_url/2), never from the response's
Content-Type.
Summary
Types
@type reason() :: :invalid_url | :scheme_not_allowed | :port_not_allowed | :blocked_host | :nxdomain | :too_many_redirects | :too_large | :timeout | {:http_status, pos_integer()} | {:connect_failed, term()} | {:write_failed, term()}