fix(19.3-03): name stored uploads after their sniffed content through attach.DiskExtension

- DiskExtension: a fixed table of specific sniffed types keeps a matching client
  extension or uses the canonical one; generic sniffs keep the client extension
  unless it is script-capable (then txt or bin); never asks package mime
- Store names the blob with DiskExtension(sniffed, ext); file_name, the allow-list
  and the stored content_type are unchanged
- TestStoreDiskExtensionSmoke: a PNG uploaded as x.html is stored and served as .png,
  report.docx keeps .docx, an HTML body named note.txt keeps .txt
- attachments docs on disk names, storage deploy note on nosniff and allow-lists,
  lagoon README
This commit is contained in:
Jakub Zych
2026-10-15 18:09:49 +02:00
parent 2382040b25
commit 2e22e9f9a6
6 changed files with 151 additions and 6 deletions

View File

@@ -95,7 +95,9 @@ type Limits struct {
// checked against the sniffed type, or the extension's registered type when
// the sniff only says application/octet-stream (else ErrMIMEType). The body
// is then streamed into bucket at BlobKey of a server-generated disk name (22
// random lowercase hex characters, a dot and the extension); a body longer
// random lowercase hex characters, a dot and the extension DiskExtension
// derives from the sniffed type and the client extension, so a PNG named
// x.html is stored as .png; file_name keeps the client's name); a body longer
// than Limits.MaxBytes aborts the write, deletes the key and returns
// ErrTooLarge. Finally it inserts the row with empty attachment columns,
// is_public from Upload.Public, the byte size and the content type, and sets
@@ -138,7 +140,8 @@ func Store(ctx context.Context, db *gorm.DB, bucket *blob.Bucket, in Upload, lim
if lim.Image && !IsAllowedImage(head) {
return nil, ErrNotImage
}
contentType := baseMediaType(http.DetectContentType(head))
sniffed := baseMediaType(http.DetectContentType(head))
contentType := sniffed
if contentType == "application/octet-stream" {
if byExt := baseMediaType(mime.TypeByExtension("." + ext)); byExt != "" {
contentType = byExt
@@ -148,7 +151,7 @@ func Store(ctx context.Context, db *gorm.DB, bucket *blob.Bucket, in Upload, lim
return nil, fmt.Errorf("%w: %s", ErrMIMEType, contentType)
}
diskName, err := newDiskName(ext)
diskName, err := newDiskName(DiskExtension(sniffed, ext))
if err != nil {
return nil, err
}