From ff616de82bfc7d0fa7085968cbdfd44502da409c Mon Sep 17 00:00:00 2001 From: LinYushen Date: Thu, 2 Apr 2026 13:55:50 +0800 Subject: [PATCH] fix(upload): remove file type allowlist to support all file types (#329) * fix(upload): remove file type allowlist to support all file types Removes the hardcoded MIME type allowlist from both frontend and backend that was blocking uploads of file types like Word documents (.docx). File size limit (10 MB) is still enforced. Content type detection is preserved for metadata storage. Closes MUL-123 * feat(upload): increase file size limit from 10 MB to 100 MB Updates both frontend and backend to allow uploads up to 100 MB. --- apps/web/shared/hooks/use-file-upload.ts | 31 ++--------------------- server/internal/handler/file.go | 32 +----------------------- 2 files changed, 3 insertions(+), 60 deletions(-) diff --git a/apps/web/shared/hooks/use-file-upload.ts b/apps/web/shared/hooks/use-file-upload.ts index 476913fa..ddfe02f9 100644 --- a/apps/web/shared/hooks/use-file-upload.ts +++ b/apps/web/shared/hooks/use-file-upload.ts @@ -5,31 +5,7 @@ import { toast } from "sonner"; import { api } from "@/shared/api"; import type { Attachment } from "@/shared/types"; -const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB - -const ALLOWED_TYPES = new Set([ - "image/png", - "image/jpeg", - "image/gif", - "image/webp", - "image/svg+xml", - "application/pdf", - "text/plain", - "text/csv", - "application/json", - "video/mp4", - "video/webm", - "audio/mpeg", - "audio/wav", - "application/zip", -]); - -function isAllowedType(type: string): boolean { - // Empty MIME type (browser couldn't determine) — let the server sniff and decide. - if (!type) return true; - const mediaType = type.split(";")[0] ?? ""; - return ALLOWED_TYPES.has(mediaType.trim().toLowerCase()); -} +const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 MB export interface UploadResult { id: string; @@ -48,10 +24,7 @@ export function useFileUpload() { const upload = useCallback( async (file: File, ctx?: UploadContext): Promise => { if (file.size > MAX_FILE_SIZE) { - throw new Error("File exceeds 10 MB limit"); - } - if (!isAllowedType(file.type)) { - throw new Error(`File type not allowed: ${file.type}`); + throw new Error("File exceeds 100 MB limit"); } setUploading(true); diff --git a/server/internal/handler/file.go b/server/internal/handler/file.go index a51711c0..c0b73454 100644 --- a/server/internal/handler/file.go +++ b/server/internal/handler/file.go @@ -9,7 +9,6 @@ import ( "log/slog" "net/http" "path" - "strings" "time" "github.com/go-chi/chi/v5" @@ -17,32 +16,7 @@ import ( db "github.com/multica-ai/multica/server/pkg/db/generated" ) -const maxUploadSize = 10 << 20 // 10 MB - -// Allowed MIME type prefixes and exact types for uploads. -var allowedContentTypes = map[string]bool{ - "image/png": true, - "image/jpeg": true, - "image/gif": true, - "image/webp": true, - "image/svg+xml": true, - "application/pdf": true, - "text/plain": true, - "text/csv": true, - "application/json": true, - "video/mp4": true, - "video/webm": true, - "audio/mpeg": true, - "audio/wav": true, - "application/zip": true, -} - -func isContentTypeAllowed(ct string) bool { - // Normalize: take only the media type, strip parameters like charset. - ct = strings.TrimSpace(strings.SplitN(ct, ";", 2)[0]) - ct = strings.ToLower(ct) - return allowedContentTypes[ct] -} +const maxUploadSize = 100 << 20 // 100 MB // --------------------------------------------------------------------------- // Response types @@ -148,10 +122,6 @@ func (h *Handler) UploadFile(w http.ResponseWriter, r *http.Request) { return } contentType := http.DetectContentType(buf[:n]) - if !isContentTypeAllowed(contentType) { - writeError(w, http.StatusBadRequest, fmt.Sprintf("file type not allowed: %s", contentType)) - return - } // Seek back so the full file is uploaded. if _, err := file.Seek(0, io.SeekStart); err != nil { writeError(w, http.StatusInternalServerError, "failed to read file")