Give every parked attachment an owner, a ceiling, and the server's own limit #111
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fase-2-bijlagen"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fase 2a van "nieuw bericht opstellen en plannen". Base:
fase-1-fundament(PR #110).Nog geen feature: dit maakt de bijlagen-laag veilig genoeg om er straks de kabel op aan te sluiten. Drie dingen die prima waren zolang je bijlagen niet kon plannen, en dat niet meer zijn zodra refs de enige munteenheid worden waarin ze rondgaan.
Een ref had geen eigenaar
Een
refis een kale UUID.DELETE /api/outgoing-files/{ref}controleerde niets, en_file_entries_from_refsvalideerde alleen dát het bestand bestond. Gebruiker A kon dus het geparkeerde bestand van gebruiker B aan zijn eigen bericht hangen - en het verwijder-endpoint was een destructieve IDOR die lag te wachten op de dag dat refs echt iets zouden dragen.Elke lees-, schrijf- en verwijderactie noemt nu de eigenaar. Afgedwongen op één plek - dezelfde waar elke route met
file_refstoch al doorheen gaat - in plaats van op vijf plekken die het elk apart moeten onthouden. Een zijbestand zónderuser_idleest als niet-gevonden: fail closed, geen gedoogregel, want een tak die zonder eigenaar tóch toegang geeft gaat nooit meer dicht.Geen 403 maar een 404: die vertelt een aanvaller niets wat een 403 niet ook zou verklappen.
Er was geen plafond
Meerdere gebruikers delen één pod en één volume. De schijf-vol-check weigert de láátste schrijfactie; hij voorkomt het volschrijven niet. Wie de schijf volzet, neemt de bijlagen van alle anderen mee.
1 GB per gebruiker (
WAGGLE_MAX_PARKED_BYTES_PER_USER), geteld over de bytes op schijf en niet over de bytes die aan een rij hangen. Een ref bereikt pas een rij zodra de gedebouncede concept-opslag eraan toekomt, dus een rij-gebaseerde som telt een verse upload als nul - en een lus die uploadt zonder ooit aan te hechten is precies waar het plafond voor bestaat.De bestandslimiet was gegokt, twee keer, verschillend
cards.pyzei 55 MB ("MM's 50 MB-default plus overhead"),outgoing_files.pyzei 100 MB. Allebei waren ooit waar: Mattermost verhoogde zijn eigen default van 50 naar 100 MB (MM-31277) en één comment liep achter.Maar het getal is niet van ons.
FileSettings.MaxFileSizeis serverconfiguratie en een beheerder kan hem verzetten. Mattermost vertelt hem gewoon aan elke ingelogde client (server/config/client.go,GenerateClientConfig), dus we vragen het bij het koppelen en bewaren het op het account.Best-effort: een server die het niet wil zeggen, is nog steeds een server die je kunt koppelen - dan vallen we terug op Mattermosts eigen default.
EnableFileAttachmentskomt mee, zodat een server met bijlagen uit ons kan tegenhouden er een paperclip op te richten.De les is niet "kies het juiste getal", maar: bezit geen getal dat van iemand anders is.
Verder
card_iddeed daar niets anders dan een eigenaarscheck dierequire_useral doet, en een geparkeerde ref legt geen kaartrelatie vast. WordtPOST /api/outgoing-files.wipe_doneverwijdert refs niet meer onvoorwaardelijk. Een gepland bericht bewerken annuleert de rij en hangt dezelfde refs aan het nieuwe concept, dus een terminale en een levende rij kunnen hetzelfde bestand delen. "Wachtrij opschonen" wiste dan de bijlage waar je op dat moment mee aan het schrijven was._delete_orphan_refskent die regel, en is nu de enige die verwijdert.docs/deployment.mdlegt de volume-eis vast, mét grootte. Die stond alleen in een comment in de Containerfile - te dun voor iets waar bijlagen van afhangen.Poorten
1358 tests groen, 100,00% backend-dekking, pre-commit groen.
Wat hierna komt (fase 2b)
De kabel écht aansluiten: de frontend van MM-
file_ids naar refs, het antwoord-endpoint vanfile_idsnaarfile_refsmet een gedeelde upload-helper, en de wees-opruimer. Pas dán kun je een bijlage bij een gepland bericht meesturen.Three things that were fine while attachments could not be scheduled, and stop being fine the moment refs become the only currency they travel in. **A ref had no owner.** It is a bare uuid, and DELETE /api/outgoing-files/{ref} checked nothing: a destructive IDOR waiting for the day refs actually carry something. _file_entries_from_refs checked only that the file existed, so a row could point at somebody else's bytes. Every read, write and delete now names the owner, enforced in one place - the one every route with file_refs already goes through - rather than in five places that each have to remember. A sidecar with no user_id reads as missing: fail closed, no grandfathering, because a branch that grants access without an owner never closes again. **There was no ceiling.** Several users share one pod and one volume. The disk-full guard refuses the last write; it does not stop the filling, and the user who fills the disk takes everyone else's attachments with them. 1 GB per user, counted over bytes on disk rather than bytes attached to a row - a ref only reaches a row when the debounced draft-save gets round to it, so a row-based sum counts a fresh upload as zero, and a loop that uploads without ever attaching is exactly what the ceiling is for. **The file-size limit was guessed, twice, differently.** cards.py said 55 MB ("MM's 50 MB default plus overhead"), outgoing_files.py said 100 MB. Both were true once: Mattermost raised its own default from 50 to 100 MB (MM-31277) and one comment never caught up. But the number is not ours - FileSettings.MaxFileSize is server configuration and an admin can move it. Mattermost hands it to every logged-in client, so we ask at link time and store it on the account. Best-effort: a server that will not tell us is still a server you can link, and we fall back to Mattermost's own default. EnableFileAttachments comes along, so a server with attachments switched off can stop us pointing a paperclip at it. The upload route loses its card. The card_id did nothing there but an ownership check that require_user already does, and a parked ref records no relationship to a card. POST /api/outgoing-files. wipe_done no longer deletes refs unconditionally. Editing a scheduled post cancels the row and hangs the same refs on the new draft, so a terminal row and a live one can share a file; _delete_orphan_refs knows that rule and is now the only place that deletes.Pull request closed