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
This commit is contained in:
1 parent
8f75317050
commit
4a713f3fb6
22 files changed
+1030
-26
No files matched your search
@@ -170,6 +170,28 @@ namespace PrivaPub.Federation.Rendering
|
||||
};
|
||||
if (!string.IsNullOrEmpty(post.Language))
|
||||
note["contentMap"] = new JsonObject { [post.Language] = content };
|
||||
var attachments = post.Media.Where(m => !string.IsNullOrEmpty(m.URL)).Select(m =>
|
||||
{
|
||||
var attachment = new JsonObject
|
||||
{
|
||||
["type"] = "Document",
|
||||
["mediaType"] = m.ContentType,
|
||||
["url"] = m.URL,
|
||||
["name"] = m.Description
|
||||
};
|
||||
if (!string.IsNullOrEmpty(m.Blurhash))
|
||||
attachment["blurhash"] = m.Blurhash;
|
||||
if (m.Focus is { Length: 2 })
|
||||
attachment["focalPoint"] = new JsonArray(m.Focus[0], m.Focus[1]);
|
||||
if (m.Width.HasValue && m.Height.HasValue)
|
||||
{
|
||||
attachment["width"] = m.Width;
|
||||
attachment["height"] = m.Height;
|
||||
}
|
||||
return (JsonNode)attachment;
|
||||
}).ToArray();
|
||||
if (attachments.Length > 0)
|
||||
note["attachment"] = new JsonArray(attachments);
|
||||
if (!string.IsNullOrEmpty(post.Title))
|
||||
note["name"] = post.Title;
|
||||
var summary = post.SpoilerText ?? (post.HasContentWarning ? post.Title ?? ContentWarning : default);
|
||||
|
||||
Reference in new issue
Block a user