An upload went straight to libvips: whatever loader recognised the bytes ran (an SVG sent as image/png was rasterised), nothing bounded how many pixels it would decode to (a small PNG could decode to gigabytes, three times over), a GIF was loaded frame by frame and never resized, and all of it ran inside the request with nothing limiting how many at once. A GIF was typed gifv but stayed a .gif, which a gifv player can't play; its metadata was kept; colours lost their ICC profile without being converted; HEIC was advertised but the bundled libvips can't decode it. Now: - only libvips' JPEG, PNG, GIF, WebP and HEIF loaders ever run on an upload (every other loader is blocked); - the header alone says how big an image would decode, refused above Media:MaxPixels (40 MP) or MaxFrames; - a still image is shrunk on load, turned by its orientation and brought into sRGB (thumbnail), then written without metadata, a profile picture the same way; - an animated GIF becomes a looping silent H.264 mp4 typed gifv, as on Mastodon (PostMedia.Kind keeps it a gifv), and a remote GIF is an image; - processing runs Media:Concurrency at a time, and uploads have their own rate limit per credential; - HEIC and HEIF are no longer offered. Tests: only the upload formats load, the header tells the size, an SVG posing as a PNG and an image too large are refused before decoding, an animated GIF becomes a gifv and a still one an image, HEIC isn't advertised. The media scenarios against the pasture (GoToSocial, Mastodon, Misskey, Akkoma, Pixelfed, Smithereen, Vernissage, Castopod, PeerTube) pass: 329 checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
38 lines
1.3 KiB
JSON
38 lines
1.3 KiB
JSON
{
|
|
"MongoSettings": {
|
|
"Database": "PrivaPub",
|
|
"LogsDatabase": "logs",
|
|
"ConnectionString": "mongodb://mongo:27017"
|
|
},
|
|
"AppConfiguration": {
|
|
"Version": "0.0.0",
|
|
"MaxAllowedUploadFiles": 3,
|
|
"MaxAllowedFileSize": 2097152,
|
|
"SupportedLanguages": [ "en" ],
|
|
"BackendBaseAddress": "https://privapub.test",
|
|
"FrontendBaseAddress": "https://privapub.test",
|
|
"HashingOptions": { "Iterations": 10101 },
|
|
"Jwt": {
|
|
"Key": "pasture-only-key-not-a-secret-pasture-only-key-not-a-secret-0123456789",
|
|
"Issuer": "http://privapub.test",
|
|
"Audience": "http://privapub.test",
|
|
"HoursTimeout": 24
|
|
}
|
|
},
|
|
"Federation": {
|
|
"AllowPrivateNetworks": true,
|
|
"AllowPlainHttp": true,
|
|
"AcceptAnyCertificate": true,
|
|
"Relays": [ "https://relay.test/actor", "https://aoderelay.test/actor" ]
|
|
},
|
|
"Media": { "Root": "/tmp/privapub-media" },
|
|
"RateLimits": { "AccountsPerMinute": 1000, "UploadsBurst": 1000, "UploadsPerMinute": 1000 },
|
|
"Registrations": { "Mode": "Open" },
|
|
"Statistics": { "Geo": { "AutoUpdate": false } },
|
|
"Kestrel": { "Endpoints": { "Http": { "Url": "http://0.0.0.0:80", "Protocols": "Http1AndHttp2" } } },
|
|
"Serilog": {
|
|
"MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning" } },
|
|
"WriteTo": [ { "Name": "Console" } ]
|
|
}
|
|
}
|