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
@@ -44,8 +44,6 @@ namespace PrivaPub.Api.Mastodon.Controllers
|
||||
if (existing != default)
|
||||
return Json(await _mapper.Status(existing, MyId, token));
|
||||
}
|
||||
if (Params.List("media_ids").Count > 0)
|
||||
return Error(StatusCodes.Status422UnprocessableEntity, "Validation failed: Media attachments are not supported yet");
|
||||
if (Params.Has("poll[options]"))
|
||||
return Error(StatusCodes.Status422UnprocessableEntity, "Validation failed: Polls are not supported yet");
|
||||
|
||||
@@ -57,7 +55,8 @@ namespace PrivaPub.Api.Mastodon.Controllers
|
||||
Sensitive = Params.Bool("sensitive") ?? Me.Settings.DefaultSensitive,
|
||||
Visibility = Visibility(Params.Get("visibility") ?? Me.Settings.DefaultVisibility),
|
||||
InReplyTo = Params.Get("in_reply_to_id"),
|
||||
Language = Params.Get("language") ?? Me.Settings.DefaultLanguage
|
||||
Language = Params.Get("language") ?? Me.Settings.DefaultLanguage,
|
||||
MediaIds = Params.List("media_ids")
|
||||
}, token);
|
||||
if (!outcome.Ok)
|
||||
return Error(outcome.Status, outcome.Error);
|
||||
@@ -88,15 +87,14 @@ namespace PrivaPub.Api.Mastodon.Controllers
|
||||
[HttpPut("/api/v1/statuses/{id}"), Scope("write:statuses")]
|
||||
public async Task<IActionResult> Edit(string id, CancellationToken token)
|
||||
{
|
||||
if (Params.List("media_ids").Count > 0)
|
||||
return Error(StatusCodes.Status422UnprocessableEntity, "Validation failed: Media attachments are not supported yet");
|
||||
var outcome = await _statuses.Edit(Me, id, new StatusDraft
|
||||
{
|
||||
Text = Params.Get("status"),
|
||||
PlainText = true,
|
||||
SpoilerText = Params.Get("spoiler_text"),
|
||||
Sensitive = Params.Bool("sensitive") ?? false,
|
||||
Language = Params.Get("language")
|
||||
Language = Params.Get("language"),
|
||||
MediaIds = Params.Has("media_ids") ? Params.List("media_ids") : default
|
||||
}, token);
|
||||
return outcome.Ok ? Json(await _mapper.Status(outcome.Post, MyId, token)) : Error(outcome.Status, outcome.Error);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user