Commit Graph
4 Commits
Author SHA1 Message Date
thepraandClaude Opus 5.5 81de470f64 P5 done: a key we cannot fetch for now gets 503, and follow/like/block ids stay private on purpose
Build / Build (push) Successful in 59s
Deploy / privapub.thepra.dev (push) Successful in 1m11s
- When a sender's key cannot be fetched because its server timed out or answered 5xx, the inbox answers 503 with
  Retry-After: 300 instead of 401, so Mastodon 4.7 retries rather than switching to RFC 9421 signatures we do not
  verify yet. The fetcher's failure cache now remembers whether a failure was temporary.
- Follow, Like, Block, Accept, Reject and Undo ids are deliberately not dereferenceable: serving them would publish
  who follows, likes and blocks whom. They are always sent with their object embedded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
2026-10-01 18:25:18 +02:00
thepraandClaude Opus 5.5 4a713f3fb6 Media: uploads stripped of metadata, attachments both ways, a remote media proxy
- /api/v1/media and /api/v2/media (and GET/PUT /api/v1/media/:id):
  images go through libvips (NetVips, its native build bundled):
  autorotated, every kind of metadata dropped (EXIF, GPS, XMP, IPTC,
  comments), capped at 4096 px, with a 640 px preview and a blurhash
  (own encoder, the reference algorithm); animated GIFs are re-encoded;
  video and audio are remuxed by ffmpeg with -map_metadata -1, never
  re-encoded, and a video gets a still preview. Files get random names
  under /var/lib/privapub/media, outside the web root deploys replace, and
  are served at /media/files with nosniff and a sandbox CSP.
- media_ids on create and edit (four at most, the persona's own, each used
  once); notes carry them as Document attachments with alt text, blurhash,
  focalPoint and size; inbound attachments were already kept.
- avatar and header uploads in update_credentials, cropped to 400x400 and
  1500x500, federated with Update{Person}.
- Remote media reaches clients only through /media/proxy/{hmac}/{url},
  fetched by the guarded client (no SVG, 40 MB cap) and cached outside the
  served root, trimmed to 5 GB; foreign avatars and headers use it too, so
  a client never contacts another server.
- MediaJanitor deletes uploads left unattached for a day.
- nginx accepts 100 MB bodies on the upload endpoints only (applied on Max).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
2026-10-01 12:22:08 +02:00
thepraandClaude Opus 5.5 e6a362c0b8 Domain blocks: suspend, silence, reject media
DomainBlock (domain, severity, reject-media, public and private comment)
covers the domain and its subdomains. Admins manage them under
/clientapi/admin/domainblocks/{list,insert,delete}; the set is kept in
memory, reloaded on every change and at most five minutes stale.

A suspended domain is refused by FederationHttp.IsAllowed, so nothing is
fetched from it and no job delivers to it, and the inbox drops its
activities with a 202 before fetching any key. Reject-media strips the
attachments of posts from that domain. Silence is recorded for the
timelines and notifications that arrive in P1.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
2026-10-01 11:25:05 +02:00
thepraandClaude Opus 5.5 ccc3597699 Every outbound federation request goes through one guarded client
Infrastructure/Http adds the client the roadmap's S3 and S4 ask for:
- the connect callback resolves the name itself and refuses loopback,
  private, link-local, CGNAT, documentation, multicast, ULA, NAT64, 6to4,
  Teredo and IPv4-mapped/compatible forms, then connects to the vetted
  address, so DNS rebinding cannot swap it afterwards;
- redirects are followed by hand, at most three, each one re-checked;
- bodies are capped at 1 MB after decompression, only JSON media types are
  read, every request has a 15 s budget, and a refused URL is not asked
  again for five minutes.

Actor and WebFinger fetches and inbox deliveries all use it. Test networks
can switch on Federation:AllowPrivateNetworks/AllowPlainHttp; startup
refuses both in Production.

PrivaPub.Tests (xUnit v3) starts with the address table and the fetcher's
limits against an in-process peer; build.yml and deploy.yml run it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
2026-10-01 10:46:09 +02:00