From 1363913352722a03e051b15297f72bf16d80106f Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Fri, 7 Nov 2025 17:39:36 +0900
Subject: (김준회) 돌체 업로드 MIME 타입 검증 문제 확장자로 처리
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ship/bulk-b4-upload-dialog.tsx                 | 51 +++++++++++++++++++++-
 1 file changed, 49 insertions(+), 2 deletions(-)

(limited to 'lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx')

diff --git a/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx b/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
index 3ff2f467..be656a48 100644
--- a/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
+++ b/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
@@ -163,9 +163,53 @@ export function BulkB4UploadDialog({
     setPendingProjectId("")
   }
   
+  // 파일 검증 함수
+  const validateFile = (file: File): { valid: boolean; error?: string } => {
+    const MAX_FILE_SIZE = 1024 * 1024 * 1024 // 1GB
+    const FORBIDDEN_EXTENSIONS = ['exe', 'com', 'dll', 'vbs', 'js', 'asp', 'aspx', 'bat', 'cmd']
+    
+    // 파일 크기 검증
+    if (file.size > MAX_FILE_SIZE) {
+      return {
+        valid: false,
+        error: `파일 크기가 1GB를 초과합니다 (${(file.size / (1024 * 1024 * 1024)).toFixed(2)}GB)`
+      }
+    }
+    
+    // 파일 확장자 검증
+    const extension = file.name.split('.').pop()?.toLowerCase()
+    if (extension && FORBIDDEN_EXTENSIONS.includes(extension)) {
+      return {
+        valid: false,
+        error: `금지된 파일 형식입니다 (.${extension})`
+      }
+    }
+    
+    return { valid: true }
+  }
+
   // 파일 선택 시 파싱
   const handleFilesChange = (files: File[]) => {
-    const parsed = files.map(file => {
+    const validFiles: File[] = []
+    const invalidFiles: string[] = []
+    
+    // 파일 검증
+    files.forEach(file => {
+      const validation = validateFile(file)
+      if (validation.valid) {
+        validFiles.push(file)
+      } else {
+        invalidFiles.push(`${file.name}: ${validation.error}`)
+      }
+    })
+    
+    // 유효하지 않은 파일이 있으면 토스트 표시
+    if (invalidFiles.length > 0) {
+      invalidFiles.forEach(msg => toast.error(msg))
+    }
+    
+    // 유효한 파일만 파싱
+    const parsed = validFiles.map(file => {
       const { docNumber, revision } = parseFileName(file.name)
       return {
         file,
@@ -429,7 +473,10 @@ export function BulkB4UploadDialog({
                     }
                   </p>
                   <p className="text-xs text-muted-foreground mt-1">
-                    PDF, DOC, DOCX, XLS, XLSX, DWG, DXF
+                    PDF, DOC, DOCX, XLS, XLSX, DWG, DXF (max 1GB per file)
+                  </p>
+                  <p className="text-xs text-red-600 mt-1 font-medium">
+                    Forbidden: .exe, .com, .dll, .vbs, .js, .asp, .aspx, .bat, .cmd
                   </p>
                 </label>
               </div>
-- 
cgit v1.2.3

