fix(05): WR-05 gate public file serving on is_public
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
package attach
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"gocloud.dev/blob"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const defaultStaticContentType = "application/octet-stream"
|
||||
@@ -14,7 +17,25 @@ const defaultStaticContentType = "application/octet-stream"
|
||||
// filename is the original disk_name or a thumb_* sibling stored in the
|
||||
// original's partition. The blob key is the validated 4-segment path;
|
||||
// unvalidated request segments never reach NewReader (T-05-13).
|
||||
//
|
||||
// This is the public-disk handler: it does not consult system_files.is_public.
|
||||
// Protected files must not be stored in this bucket (Winter uses a second
|
||||
// disk). To 404 is_public=false rows, mount StaticHandlerPublic instead.
|
||||
// Do not mount the ungated handler on the app origin — same-origin
|
||||
// Content-Type from uploads is XSS-relevant.
|
||||
func StaticHandler(bucket *blob.Bucket, prefix string) http.Handler {
|
||||
return servePublicBlobs(bucket, prefix, nil)
|
||||
}
|
||||
|
||||
// StaticHandlerPublic is StaticHandler plus an is_public gate. Missing
|
||||
// rows and is_public=false both 404. The lookup runs before NewReader.
|
||||
func StaticHandlerPublic(bucket *blob.Bucket, prefix string, db *gorm.DB) http.Handler {
|
||||
return servePublicBlobs(bucket, prefix, func(ctx context.Context, filename string) (bool, error) {
|
||||
return fileIsPublic(ctx, db, filename)
|
||||
})
|
||||
}
|
||||
|
||||
func servePublicBlobs(bucket *blob.Bucket, prefix string, allow func(context.Context, string) (bool, error)) http.Handler {
|
||||
prefix = strings.TrimSuffix(prefix, "/")
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet && r.Method != http.MethodHead {
|
||||
@@ -35,6 +56,13 @@ func StaticHandler(bucket *blob.Bucket, prefix string) http.Handler {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if allow != nil {
|
||||
ok, err := allow(r.Context(), path.Base(key))
|
||||
if err != nil || !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
reader, err := bucket.NewReader(r.Context(), key, nil)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
|
||||
Reference in New Issue
Block a user