Require a signed URL to write to the local

This commit is contained in:
bcmmbaga
2026-09-09 18:21:52 +03:00
parent bb4de1d008
commit e5900f493c
4 changed files with 277 additions and 21 deletions
+28 -13
View File
@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"strings"
"time"
log "github.com/sirupsen/logrus"
@@ -20,8 +21,9 @@ const (
)
type local struct {
url string
dir string
url string
dir string
signer *signer
}
func configureLocalHandlers(mux *http.ServeMux) error {
@@ -44,9 +46,15 @@ func configureLocalHandlers(mux *http.ServeMux) error {
dir = envDir
}
uploadSigner, err := newSigner()
if err != nil {
return err
}
l := &local{
url: envURL,
dir: dir,
url: envURL,
dir: dir,
signer: uploadSigner,
}
mux.HandleFunc(types.GetURLPath, l.handlerGetUploadURL)
mux.HandleFunc(putURLPath+putHandler, l.handlePutRequest)
@@ -80,6 +88,7 @@ func (l *local) getUploadURL(objectKey string) (string, error) {
return "", fmt.Errorf("failed to parse upload URL: %w", err)
}
newURL := parsedUploadURL.JoinPath(parsedUploadURL.Path, putURLPath, objectKey)
newURL.RawQuery = l.signer.sign(objectKey, time.Now()).Encode()
return newURL.String(), nil
}
@@ -91,13 +100,6 @@ func (l *local) handlePutRequest(w http.ResponseWriter, r *http.Request) {
return
}
r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "request body too large or failed to read", http.StatusRequestEntityTooLarge)
return
}
uploadDir := r.PathValue("dir")
if uploadDir == "" {
http.Error(w, "missing dir path", http.StatusBadRequest)
@@ -109,6 +111,19 @@ func (l *local) handlePutRequest(w http.ResponseWriter, r *http.Request) {
return
}
if err := l.signer.verify(uploadDir+"/"+uploadFile, r.URL.Query(), time.Now()); err != nil {
http.Error(w, "unauthorized", http.StatusUnauthorized)
log.Warnf("Rejected upload of %s/%s: %v", uploadDir, uploadFile, err)
return
}
r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "request body too large or failed to read", http.StatusRequestEntityTooLarge)
return
}
cleanBase := filepath.Clean(l.dir) + string(filepath.Separator)
dirPath := filepath.Clean(filepath.Join(l.dir, uploadDir))
@@ -125,14 +140,14 @@ func (l *local) handlePutRequest(w http.ResponseWriter, r *http.Request) {
return
}
if err = os.MkdirAll(dirPath, 0750); err != nil {
if err = os.MkdirAll(dirPath, 0o750); err != nil {
http.Error(w, "failed to create upload dir", http.StatusInternalServerError)
log.Errorf("Failed to create upload dir: %v", err)
return
}
flags := os.O_WRONLY | os.O_CREATE | os.O_EXCL
f, err := os.OpenFile(filePath, flags, 0600)
f, err := os.OpenFile(filePath, flags, 0o600)
if err != nil {
if os.IsExist(err) {
http.Error(w, "file already exists", http.StatusConflict)