From 4b637fb689aea8605cae268e6eaf26a34c759a00 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 9 Sep 2026 17:18:59 +0000 Subject: [PATCH 1/7] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=93=9C=EB=A1=AD=EC=A1=B4=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 드롭존에 올바르지 않은 타입의 파일(예: 텍스트 파일)을 놓았을 때 명확한 오류 메시지와 함께 `aria-invalid` 상태가 업데이트되도록 클라이언트 측 검증 로직을 추가했습니다. --- .jules/palette.md | 3 +++ saas_web.py | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/.jules/palette.md b/.jules/palette.md index 2dcd639e..fb0e12e7 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -81,3 +81,6 @@ ## 2024-08-04 - 숫자 입력 필드 빈 문자열 상태 초기화 처리 **학습:** 숫자 입력 필드에서 빈 문자열('')을 입력할 때 브라우저는 이전의 유효하지 않은 상태를 암시적으로 유지하므로, 사용자 정의 검증을 명시적으로 초기화하지 않으면 네이티브 HTML5 유효성 검사가 정상 작동하지 않을 수 있음을 확인했습니다. **실행:** 인라인 검증 스크립트 작성 시 빈 문자열 상태를 별도로 확인하여 this.setCustomValidity('') 및 this.removeAttribute('aria-invalid')를 명시적으로 호출하는 로직을 추가해야 합니다. +## 2024-08-05 - File type validation for drop zones +**Learning:** The HTML `accept` attribute does not reliably prevent invalid files from being dropped. Always add explicit client-side JavaScript validation against `file.type` and provide inline accessibility feedback using `setCustomValidity` and `aria-invalid` to ensure a smooth, accessible user experience. +**Action:** Add explicit client-side validation against `file.type` for all file inputs and drop zones. diff --git a/saas_web.py b/saas_web.py index 63265e94..04180626 100644 --- a/saas_web.py +++ b/saas_web.py @@ -228,6 +228,13 @@ async def add_security_headers(request: Request, call_next): preview.innerText = ''; return; } + if (file.type && !file.type.startsWith('audio/') && !file.type.startsWith('video/')) { + input.setCustomValidity('Unsupported file type. Please select an audio or video file.'); + input.setAttribute('aria-invalid', 'true'); + preview.innerText = 'Unsupported file type (' + file.type + '). Please select an audio or video file.'; + preview.style.color = '#dc3545'; + return; + } const text = formatBinaryBytes(file.size); if (file.size > MAX_UPLOAD_BYTES) { const limitText = formatBinaryBytes(MAX_UPLOAD_BYTES); @@ -329,8 +336,24 @@ async def add_security_headers(request: Request, call_next): } let totalSize = 0; + let hasInvalidType = false; + let invalidType = ''; for (let i = 0; i < files.length; i++) { - totalSize += files[i].size; + const f = files[i]; + if (f.type && !f.type.startsWith('audio/') && !f.type.startsWith('video/')) { + hasInvalidType = true; + invalidType = f.type; + break; + } + totalSize += f.size; + } + + if (hasInvalidType) { + input.setCustomValidity('Unsupported file type. Please select audio or video files only.'); + input.setAttribute('aria-invalid', 'true'); + preview.innerText = 'Unsupported file type (' + invalidType + ') detected. Please select audio or video files only.'; + preview.style.color = '#dc3545'; + return; } if (files.length > 20) { From db430c51cc77e91fe8bfd96b6586c0d90291078b Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 9 Sep 2026 17:25:06 +0000 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=93=9C=EB=A1=AD=EC=A1=B4=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 드롭존에 올바르지 않은 타입의 파일(예: 텍스트 파일)을 놓았을 때 명확한 오류 메시지와 함께 `aria-invalid` 상태가 업데이트되도록 클라이언트 측 검증 로직을 추가했습니다. From f65ca5011598f08bbe2b08ff8f4eb4b6a728065c Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 9 Sep 2026 17:28:29 +0000 Subject: [PATCH 3/7] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=93=9C=EB=A1=AD=EC=A1=B4=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 드롭존에 올바르지 않은 타입의 파일(예: 텍스트 파일)을 놓았을 때 명확한 오류 메시지와 함께 `aria-invalid` 상태가 업데이트되도록 클라이언트 측 검증 로직을 추가했습니다. From 21ed195330907f82654da051450e60711755b429 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 9 Sep 2026 17:32:32 +0000 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=93=9C=EB=A1=AD=EC=A1=B4=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 드롭존에 올바르지 않은 타입의 파일(예: 텍스트 파일)을 놓았을 때 명확한 오류 메시지와 함께 `aria-invalid` 상태가 업데이트되도록 클라이언트 측 검증 로직을 추가했습니다. From 355ab5019da4d49c2b400247db43a93371e823b6 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 9 Sep 2026 17:34:00 +0000 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=93=9C=EB=A1=AD=EC=A1=B4=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 드롭존에 올바르지 않은 타입의 파일(예: 텍스트 파일)을 놓았을 때 명확한 오류 메시지와 함께 `aria-invalid` 상태가 업데이트되도록 클라이언트 측 검증 로직을 추가했습니다. From c13f20487b70bba45c6b12f639aab89a16996b6a Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 9 Sep 2026 17:38:43 +0000 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=93=9C=EB=A1=AD=EC=A1=B4=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 드롭존에 올바르지 않은 타입의 파일(예: 텍스트 파일)을 놓았을 때 명확한 오류 메시지와 함께 `aria-invalid` 상태가 업데이트되도록 클라이언트 측 검증 로직을 추가했습니다. From 3cb30c058db05c590257e706a9c19f6d7bd1cffd Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 9 Sep 2026 17:42:04 +0000 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=93=9C=EB=A1=AD=EC=A1=B4=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 드롭존에 올바르지 않은 타입의 파일(예: 텍스트 파일)을 놓았을 때 명확한 오류 메시지와 함께 `aria-invalid` 상태가 업데이트되도록 클라이언트 측 검증 로직을 추가했습니다.