docs: capture todo - blob writers that bypass attach.Store set Content-Disposition

This commit is contained in:
Jakub Zych
2026-11-06 09:18:55 +01:00
parent 895248eef2
commit 9fa740e8b7

View File

@@ -0,0 +1,27 @@
---
created: 2026-11-06T08:17:49.419Z
title: Blob writers that bypass attach.Store set Content-Disposition for non-inline types
area: framework
severity: minor
g15office: ifdz5o0m
files:
- modules/lagoon/attach/inline.go:31 (IsInlineContentType), :38 (uploadWriterOptions, unexported)
- ../fonoteka.go/plugins/golem15/fonoteka/controllers/api/collection_media_controller.go:258 (storeUpload)
- ../fonoteka.go/plugins/golem15/fonoteka/classes/album_files.go:42 (StorePublicFile)
- ../sm-user-plugin/controllers/api_controller.go:1559 (avatar upload)
- ../sm-feedback-plugin/classes/submission_store.go:131 (screenshot)
---
## Problem
Follow-up of g15office knuu7fil (closed by summercms.go 27c98bf). `attach.Store` stores every non-inline type (anything but JPEG/PNG/GIF/WebP/AVIF) with `Content-Disposition: attachment`, and `attach.StaticHandler` / `StaticHandlerPublic` now send the stored disposition plus `nosniff`. Writers that call `bucket.NewWriter` / `WriteAll` themselves pass only `ContentType`, so their blobs carry no disposition and an HTML or SVG blob is served inline by the static handlers (or by a web server reading the bucket directly).
Writers that bypass `attach.Store`:
- fonoteka.go `storeUpload` and `StorePublicFile`: accept arbitrary media, so this is the real gap. The disk-extension issue at the same call sites is the separate major todo `2026-10-28-fonoteka-uploads-use-disk-extension.md` (cf81chjk); do both together.
- sm-user-plugin avatar upload and sm-feedback-plugin screenshots: inputs are already limited to images, so this is defence in depth.
## Solution
- Framework (additive): export the writer-options helper, e.g. `attach.UploadWriterOptions(contentType) *blob.WriterOptions`, with README and docs updated in the same commit. Writers can also check `attach.IsInlineContentType` themselves, or switch to `attach.Store`.
- Each writer uses it. Shared plugins: additive change only, plugin commit and patch tag first, then pointer bumps in the apps as separate commits. A plugin using a new framework export needs the framework tag that has it, so raise the plugin's required version only if consumers are already on that version; otherwise inline the `IsInlineContentType` check.
- Regression test per writer: an upload whose sniffed type isn't an inline image is stored with `attachment` disposition.