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-vendor-document/add-attachment-dialog.tsx | 55 ++++++++++++++++++++--
 1 file changed, 51 insertions(+), 4 deletions(-)

(limited to 'components/ship-vendor-document/add-attachment-dialog.tsx')

diff --git a/components/ship-vendor-document/add-attachment-dialog.tsx b/components/ship-vendor-document/add-attachment-dialog.tsx
index 6765bcf5..4a51c3b5 100644
--- a/components/ship-vendor-document/add-attachment-dialog.tsx
+++ b/components/ship-vendor-document/add-attachment-dialog.tsx
@@ -38,7 +38,7 @@ import { useSession } from "next-auth/react"
  * -----------------------------------------------------------------------------------------------*/
 
 // 파일 검증 스키마
-const MAX_FILE_SIZE = 1024 * 1024 * 1024 // 50MB
+const MAX_FILE_SIZE = 1024 * 1024 * 1024 // 1GB
 const ACCEPTED_FILE_TYPES = [
   'application/pdf',
   'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
@@ -73,7 +73,7 @@ const attachmentUploadSchema = z.object({
     // .max(10, "Maximum 10 files can be uploaded")
     .refine(
       (files) => files.every((file) => file.size <= MAX_FILE_SIZE),
-      "File size must be 50MB or less"
+      "File size must be 1GB or less"
     )
     // .refine(
     //   (files) => files.every((file) => ACCEPTED_FILE_TYPES.includes(file.type)),
@@ -101,10 +101,46 @@ function FileUploadArea({
 }) {
   const fileInputRef = React.useRef<HTMLInputElement>(null)
 
+  // 파일 검증 함수
+  const validateFiles = (filesToValidate: File[]): { valid: File[], invalid: string[] } => {
+    const MAX_FILE_SIZE = 1024 * 1024 * 1024 // 1GB
+    const FORBIDDEN_EXTENSIONS = ['exe', 'com', 'dll', 'vbs', 'js', 'asp', 'aspx', 'bat', 'cmd']
+    
+    const valid: File[] = []
+    const invalid: string[] = []
+    
+    filesToValidate.forEach(file => {
+      // 파일 크기 검증
+      if (file.size > MAX_FILE_SIZE) {
+        invalid.push(`${file.name}: 파일 크기가 1GB를 초과합니다 (${formatFileSize(file.size)})`)
+        return
+      }
+      
+      // 파일 확장자 검증
+      const extension = file.name.split('.').pop()?.toLowerCase()
+      if (extension && FORBIDDEN_EXTENSIONS.includes(extension)) {
+        invalid.push(`${file.name}: 금지된 파일 형식입니다 (.${extension})`)
+        return
+      }
+      
+      valid.push(file)
+    })
+    
+    return { valid, invalid }
+  }
+
   const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
     const selectedFiles = Array.from(event.target.files || [])
     if (selectedFiles.length > 0) {
-      onFilesChange([...files, ...selectedFiles])
+      const { valid, invalid } = validateFiles(selectedFiles)
+      
+      if (invalid.length > 0) {
+        invalid.forEach(msg => toast.error(msg))
+      }
+      
+      if (valid.length > 0) {
+        onFilesChange([...files, ...valid])
+      }
     }
   }
 
@@ -112,7 +148,15 @@ function FileUploadArea({
     event.preventDefault()
     const droppedFiles = Array.from(event.dataTransfer.files)
     if (droppedFiles.length > 0) {
-      onFilesChange([...files, ...droppedFiles])
+      const { valid, invalid } = validateFiles(droppedFiles)
+      
+      if (invalid.length > 0) {
+        invalid.forEach(msg => toast.error(msg))
+      }
+      
+      if (valid.length > 0) {
+        onFilesChange([...files, ...valid])
+      }
     }
   }
 
@@ -147,6 +191,9 @@ function FileUploadArea({
         <p className="text-xs text-muted-foreground">
           Supports PDF, Word, Excel, Image, Text, ZIP, CAD files (DWG, DXF, STEP, STL, IGES) (max 1GB)
         </p>
+        <p className="text-xs text-red-600 mt-1 font-medium">
+          Forbidden file types: .exe, .com, .dll, .vbs, .js, .asp, .aspx, .bat, .cmd
+        </p>
         <p className="text-xs text-orange-600 mt-1">
           Note: File names cannot contain these characters: &lt; &gt; : &quot; &apos; | ? *
         </p>
-- 
cgit v1.2.3

