package handlers import ( "errors" "fmt" "mime/multipart" "net/http" "strconv" "strings" "warpbox.dev/backend/libs/helpers" "warpbox.dev/backend/libs/jobs" "warpbox.dev/backend/libs/services" ) func (a *App) Upload(w http.ResponseWriter, r *http.Request) { user, loggedIn := a.currentUser(r) isAdminUpload := loggedIn && user.Role == services.UserRoleAdmin if !isAdminUpload { r.Body = http.MaxBytesReader(w, r.Body, a.uploadService.MaxUploadSize()*8) } parseLimit := a.uploadService.MaxUploadSize() * 8 if isAdminUpload { parseLimit = 32 << 20 } if err := r.ParseMultipartForm(parseLimit); err != nil { helpers.WriteJSONError(w, http.StatusBadRequest, "upload form could not be read") return } files := uploadFiles(r) var ownerID string var collectionID string if loggedIn { ownerID = user.ID collectionID = r.FormValue("collection_id") if !a.authService.CollectionOwnedBy(collectionID, user.ID) { helpers.WriteJSONError(w, http.StatusForbidden, "collection not found") return } } result, err := a.uploadService.CreateBox(files, services.UploadOptions{ MaxDays: parseInt(r.FormValue("max_days")), MaxDownloads: parseInt(r.FormValue("max_downloads")), Password: r.FormValue("password"), ObfuscateMetadata: r.FormValue("obfuscate_metadata") == "on", OwnerID: ownerID, CollectionID: collectionID, SkipSizeLimit: isAdminUpload, }) if err != nil { a.logger.Warn("upload failed", "source", "user-upload", "severity", "warn", "code", 4001, "error", err.Error()) helpers.WriteJSONError(w, http.StatusBadRequest, err.Error()) return } jobs.GenerateThumbnailsForBoxAsync(a.uploadService, a.logger, result.BoxID) if wantsJSON(r) { helpers.WriteJSON(w, http.StatusCreated, result) return } w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusCreated) _, _ = fmt.Fprintln(w, result.BoxURL) } func parseInt(value string) int { if value == "" { return 0 } parsed, err := strconv.Atoi(value) if err != nil { return 0 } return parsed } func statusForDownloadError(err error) int { if errors.Is(err, http.ErrMissingFile) { return http.StatusNotFound } return http.StatusForbidden } func uploadFiles(r *http.Request) []*multipart.FileHeader { if r.MultipartForm == nil { return nil } files := make([]*multipart.FileHeader, 0) files = append(files, r.MultipartForm.File["file"]...) files = append(files, r.MultipartForm.File["sharex"]...) return files } func wantsJSON(r *http.Request) bool { return strings.Contains(strings.ToLower(r.Header.Get("Accept")), "application/json") }