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(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) => { 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({

Supports PDF, Word, Excel, Image, Text, ZIP, CAD files (DWG, DXF, STEP, STL, IGES) (max 1GB)

+

+ Forbidden file types: .exe, .com, .dll, .vbs, .js, .asp, .aspx, .bat, .cmd +

Note: File names cannot contain these characters: < > : " ' | ? *

-- cgit v1.2.3