Two related changes that ensure remote images render inline in timelines
instead of as clickable links.
reverse_proxy: always force inline for whitelisted content types
When `inline_content_types` is configured as a whitelist, the upstream's
`content-disposition` header used to be passed through unchanged. Some
origins send `content-disposition: attachment` for media we want
embedded, so the proxy now always emits `content-disposition: inline`
for whitelisted types (overriding the upstream header), deriving a
filename from `MIME.extensions/1` (e.g. `inline.gif`) so browsers have
something to use for "Save As". When the type has no known extension,
the bare token `inline` is emitted. The `inline_content_types: true`
(pass-through) and `:false` (always attachment) behaviours are
unchanged.
ActivityPub: sniff MIME type for extensionless/generic attachments
Some remotes (e.g. extensionless Cloudflare Images URLs) ship
attachments with no usable `mediaType` (missing, empty, or
`application/octet-stream`), which would render as links instead of
inline images. `AttachmentValidator.fix_media_type/1` now fetches the
first 8 KB of the URL and runs it through libmagic when the declared
type carries no real information. Only `image/*` results replace the
declared type; any other result, non-2xx response, transport error, or
exception yields `nil` and the original type is kept, so ingestion
never blocks and non-image media is never reclassified. Present real
types are left untouched (no fetch is attempted).
The new logic lives in `Pleroma.Web.ActivityPub.ObjectValidators.AttachmentTypeSniffer`.
Tests: comprehensive coverage of both changes, including a dedicated
suite for the sniffer covering happy paths, non-image bodies, HTTP
failures, raised exceptions, guard clauses, and verification that the
Range header is sent; AttachmentValidator tests for mimeType fallback,
empty-string mediaType, multi-URL sniffing, and HTTP-failure fallback;
ReverseProxy tests for inline_content_types `true`/`false`/custom
whitelists, bare-inline for types without a MIME extension, and
attachment_name handling.
The core feed reader issue was that RSS 2.0 <link> is a simple text
element and can only appear once per <item>.
By having multiple <link> tags with rel attributes, parsers were
getting confused and resolving entries to the wrong URL.
Now each item has exactly one <link>: the post URL. Everything else
uses valid <atom:link> or dedicated extension elements where
appropriate.
Elixir 1.19 started lazily loading modules, so modules only get loaded
when referenced. Thus :code.all_loaded would no longer include all MRF
policies which is used on startup to generate sugestions for AdminAPI.
Checking against the default port of the Endpoint URL scheme is
redundant as normal instances will have the combination https/443
by default created by pleroma.instance gen, Tor-only instances should
have combination http/80 and local testing instances httt/XXXX.
The default scheme port doesn't add anything usefull in these configs.
increase_vote_count/3 was incrementing votersCount on every vote
activity, causing inflation when a single voter picks multiple options.
Now only increments when the actor is a new unique voter, and preserves
existing votersCount otherwise.
Also adds is_integer guard to voters_count/1 to handle nil safely, and
adds tests for the voters_count clause ordering and edge cases.