khatru/blossom: ensure we don't get tricked by Content-Length.

This commit is contained in:
fiatjaf
2026-01-16 08:12:30 -03:00
parent 8b9e2ea951
commit bd55c22768

View File

@@ -3,6 +3,7 @@ package blossom
import ( import (
"crypto/sha256" "crypto/sha256"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"mime" "mime"
"net/http" "net/http"
@@ -67,13 +68,13 @@ func (bs BlossomServer) handleUpload(w http.ResponseWriter, r *http.Request) {
// get the file size from the incoming header // get the file size from the incoming header
size, _ := strconv.Atoi(r.Header.Get("Content-Length")) size, _ := strconv.Atoi(r.Header.Get("Content-Length"))
if size == 0 { if size <= 0 {
blossomError(w, "missing \"Content-Length\" header", 400) blossomError(w, "missing \"Content-Length\" header", 400)
return return
} }
// read first bytes of upload so we can find out the filetype // read first bytes of upload so we can find out the filetype
b := make([]byte, min(50, size), size) b := make([]byte, min(50, size), size+1 /* the extra 1 is for checking the validity of the Content-Length */)
if n, err := r.Body.Read(b); err != nil && n != size { if n, err := r.Body.Read(b); err != nil && n != size {
blossomError(w, "failed to read initial bytes of upload body: "+err.Error(), 400) blossomError(w, "failed to read initial bytes of upload body: "+err.Error(), 400)
return return
@@ -102,25 +103,28 @@ func (bs BlossomServer) handleUpload(w http.ResponseWriter, r *http.Request) {
} }
// if it passes then we have to read the entire thing into memory so we can compute the sha256 // if it passes then we have to read the entire thing into memory so we can compute the sha256
for { // we will only read as much as specified in the Content-Length header
var n int if size > len(b) {
n, err = r.Body.Read(b[len(b):cap(b)]) alreadyRead := len(b)
b = b[:len(b)+n] for {
if err != nil { n, err := r.Body.Read(b[alreadyRead : size+1])
alreadyRead += n
if err == io.EOF { if err == io.EOF {
err = nil break
} else if err != nil && err != io.EOF {
blossomError(w, "failed to read upload body: "+err.Error(), 400)
return
}
if alreadyRead > size {
blossomError(w, "file is bigger than was specified in Content-Length", 400)
return
} }
break
} }
if len(b) == cap(b) { if alreadyRead != size {
// add more capacity (let append pick how much) blossomError(w, fmt.Sprintf("got a %d bytes but Content-Length said %d", alreadyRead, size), 400)
// if Content-Length was correct we shouldn't reach this return
b = append(b, 0)[:len(b)]
} }
} b = b[0:size]
if err != nil {
blossomError(w, "failed to read upload body: "+err.Error(), 400)
return
} }
hash := sha256.Sum256(b) hash := sha256.Sum256(b)