A provider link can now carry `iconUrl`, an https address of the site's
own logo. The confirmation dialog downloads it as soon as it opens and
shows it at the top; importing stores it as the card's custom icon. No
extra confirmation step. Any failure is silent: the card falls back to
the built-in `icon` name, or to the name's initials.
The image goes through the same path as a local upload: the backend
returns a data URI, the frontend redraws it on a canvas into a 96x96 PNG,
and the provider save validation checks it again. The address itself is
never stored or rendered, and the import command never downloads.
The download (`deeplink/icon_fetch.rs`):
- Parsing drops addresses that are not https, use an IP or a non-default
port, carry credentials or exceed 2048 characters; the rest of the link
still imports.
- Every resolved address must be public, and the connection is pinned to
them so a second DNS answer cannot point it elsewhere. Redirects are
followed by hand, up to 3, and each hop is checked again.
- No system proxy, no cookies, no Referer, 5 s overall timeout, body read
as a stream and capped at 256 KB.
- Content-Type must be PNG, JPEG, WebP or SVG and match the file's magic
bytes; bitmap dimensions are read from the header and capped at 4096.
- 198.18.0.0/15 is allowed on purpose: Clash and Surge fake-ip mode
resolve every domain into it. The trade-off is written next to
`is_public_ipv4`.
- Errors are logged without the URL, which may carry query tokens.
Closes#8117