Signed-in app downloads are cached privately, not publicly
CI & Build / Python lint (push) Successful in 3s
CI & Build / Build now, or wait for Android? (push) Successful in 3s
Android / Build, or is the channel already serving this? (push) Successful in 3s
Android / Core and FFI clippy and tests (push) Skipped
Android / Kotlin + Rust (APK) (push) Skipped
Android / Build the server image (push) Skipped
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 3s
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Skipped
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
CI & Build / Web typecheck and unit tests (push) Successful in 10s
CI & Build / Python tests (push) Successful in 15s
CI & Build / integration (push) Successful in 1m6s
CI & Build / Build & push image (push) Successful in 49s

Quart's send_file marks every file it sends Cache-Control: public. The app
download is behind a login, so a shared cache or proxy could have kept one
account's copy and handed it to anyone. send_artifact now marks it
private, as the attachment route already does. Family idea #5105,
practice 11 (Scribe #5113).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 09:33:48 -04:00
co-authored by Claude Opus 5.5
parent 97b04f9f92
commit 65f004029b
2 changed files with 13 additions and 0 deletions
+4
View File
@@ -424,6 +424,10 @@ async def send_artifact(root: Path, platform: Platform, found: dict) -> Response
root, platform.artifact, mimetype=platform.mimetype, add_etags=False, conditional=False root, platform.artifact, mimetype=platform.mimetype, add_etags=False, conditional=False
) )
response.set_etag(found["sha256"]) response.set_etag(found["sha256"])
# Only behind a login, so no shared cache may keep a copy (family idea #5105,
# practice 11). Quart marks every file it sends `public`.
response.cache_control.public = False
response.cache_control.private = True
# Without this some browsers try to render it, and Android's download handler # Without this some browsers try to render it, and Android's download handler
# wants a filename to hand to the package installer. # wants a filename to hand to the package installer.
response.headers["Content-Disposition"] = f'attachment; filename="{platform.artifact}"' response.headers["Content-Disposition"] = f'attachment; filename="{platform.artifact}"'
+9
View File
@@ -448,6 +448,15 @@ async def test_the_etag_is_the_sha256_the_sidecar_records(app):
assert body == PAYLOAD assert body == PAYLOAD
async def test_signed_in_bytes_are_never_cached_by_a_shared_cache(app):
"""Quart sends files `public`; behind a login that would let a proxy hand one
account's download to anyone."""
resp, _ = await _send(app, {})
directives = {d.strip().split("=")[0] for d in resp.headers["Cache-Control"].split(",")}
assert "private" in directives
assert "public" not in directives
async def test_a_range_request_gets_just_that_range(app): async def test_a_range_request_gets_just_that_range(app):
resp, body = await _send(app, {"Range": "bytes=4-9"}) resp, body = await _send(app, {"Range": "bytes=4-9"})
assert resp.status_code == 206 assert resp.status_code == 206