feat: enforce server-side upload limits (5 GiB/upload, 5 GiB rolling/email)#103
Merged
rubenhensen merged 1 commit intomainfrom Apr 23, 2026
Merged
feat: enforce server-side upload limits (5 GiB/upload, 5 GiB rolling/email)#103rubenhensen merged 1 commit intomainfrom
rubenhensen merged 1 commit intomainfrom
Conversation
…/email) Adds server-side enforcement for the upload quotas described in cryptify#100. - Rejects any chunk that would push the current upload past 5 GiB, returning 413 with a JSON body identifying the per_upload limit, used_bytes, and limit_bytes. - At finalize time, once the sender email is known from the postguard attributes, checks the sender's usage in the last 14 days. If the upload would push the sender past 15 GiB, returns 413 with limit="rolling_window" and cleans up both the FileState and the on-disk file. - Records successful finalizations against the sender email so the rolling window is actually tracked. - Exposes GET /usage?email=... so the frontend can show warnings before hitting the limit. Response includes used_bytes, limit_bytes, window_days, per_upload_limit_bytes, and resets_at (RFC-3339, when the oldest recorded upload falls out of the window). Also documents the new endpoint and 413 responses in api-description.yaml. Refs #100 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
rubenhensen
approved these changes
Apr 23, 2026
Contributor
Author
|
Dobby sees the approval! 🧦 Dobby is so happy rubenhensen approved the upload-limits PR! Dobby notes it is already merged — Dobby's work here is done, Dobby will go rest his ears now! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds server-side enforcement of upload quotas described in #100:
GET /usage?email=...— returnsused_bytes,limit_bytes,window_days,per_upload_limit_bytes, andresets_atso the frontend can warn users proactively.Closes #100.
Why at finalize and not at init?
The
FileState.senderis only populated at finalize time by reading thepbdf.sidn-pbdf.email.emailattribute out of the encrypted blob. Checking earlier would require trusting a client-supplied header, which can be bypassed — the whole point of this change is that bypass is what we want to prevent. The per-upload 5 GiB check runs on every chunk, so a malicious client still can't silently burn storage; they just waste their own bandwidth up to the limit.413 body shape
Both rejection paths return the same JSON shape:
{ "error": "human-readable explanation", "limit": "per_upload" | "rolling_window", "used_bytes": 123, "limit_bytes": 5368709120 }Usage endpoint shape
{ "email": "alice@example.com", "used_bytes": 2147483648, "limit_bytes": 5368709120, "window_days": 14, "per_upload_limit_bytes": 5368709120, "resets_at": "2026-05-05T12:00:00Z" }resets_atis the moment the oldest recorded upload falls out of the rolling window (a partial quota reset), ornullif the sender has no recorded uploads.Units
Values are GiB (binary), i.e. 5·1024³. Documented in
api-description.yamland in the 413 response body.Tests
Unit tests for the usage tracker in
src/store.rs:Run with
cargo test. All pass.Full end-to-end testing (init → chunked upload → finalize) requires a running PKG and mailcrab, which isn't available in this dev environment. The handler logic is exercised at compile time; edge cases covered by the store unit tests.
Known follow-ups (out of scope)
src/store.rsFileStateand routes insrc/main.rs. Whichever merges second needs a small rebase.Test plan
cargo checkcleancargo test— 5/5 new tests passcargo clippy --all-targets— no new warnings (pre-existingemail.rs:225warning untouched)Refs encryption4all/postguard-website#85, encryption4all/postguard-website#87.