Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 2024-05-18 - [파일 μ—…λ‘œλ“œ UX κ°œμ„ ]
**Learning:** 파일 μž…λ ₯ μš”μ†Œ(input type="file")의 크기가 μž‘κ±°λ‚˜ 클릭 μ˜μ—­μ΄ λͺ…ν™•ν•˜μ§€ μ•Šμ„ λ•Œ, μ‚¬μš©μžλ“€μ€ μ£Όλ³€μ˜ 넓은 μ˜μ—­(예: λ“œλž˜κ·Έ μ•€ λ“œλ‘­ μ˜μ—­ 전체)을 ν΄λ¦­ν•˜λ €λŠ” κ²½ν–₯이 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό μΈμ§€ν•˜μ§€ λͺ»ν•˜κ³  파일 선택 창이 열리지 μ•ŠμœΌλ©΄ 닡닡함을 λŠλ‚„ 수 μžˆμŠ΅λ‹ˆλ‹€.
**Action:** 파일 μ—…λ‘œλ“œλ₯Ό μœ„ν•œ μ»¨ν…Œμ΄λ„ˆκ°€ μžˆλ‹€λ©΄(예: .box), 전체 μ»¨ν…Œμ΄λ„ˆμ— 클릭 이벀트λ₯Ό μ—°κ²°ν•˜μ—¬ μˆ¨κ²¨μ§„ 파일 input의 click 이벀트λ₯Ό ν”„λ‘œκ·Έλž¨μ μœΌλ‘œ νŠΈλ¦¬κ±°ν•˜λ„λ‘ κ΅¬ν˜„ν•©λ‹ˆλ‹€. 이 λ•Œ `cursor: pointer` μŠ€νƒ€μΌμ„ ν•΄λ‹Ή μ»¨ν…Œμ΄λ„ˆμ— λͺ…μ‹œμ μœΌλ‘œ μ£Όμ–΄ μ‚¬μš©μžμ—κ²Œ 클릭 κ°€λŠ₯함을 μΈμ§€μ‹œν‚΅λ‹ˆλ‹€. μ»¨ν…Œμ΄λ„ˆ λ‚΄μ˜ λ‹€λ₯Έ μƒν˜Έμž‘μš© μš”μ†Œ(λ²„νŠΌ, μž…λ ₯ ν•„λ“œ λ“±)λ₯Ό 클릭할 λ•Œ 좩돌이 λ°œμƒν•˜μ§€ μ•Šλ„λ‘, `e.target.closest('input, button, label')`λ₯Ό μ‚¬μš©ν•˜μ—¬ λ‚΄λΆ€ μš”μ†Œ 클릭을 μ•ˆμ „ν•˜κ²Œ λ¬΄μ‹œν•©λ‹ˆλ‹€.
## 2024-05-18 - [파일 μ—…λ‘œλ“œ UX κ°œμ„ ]
**Learning:** 파일 μž…λ ₯ μš”μ†Œ(input type="file")의 크기가 μž‘κ±°λ‚˜ 클릭 μ˜μ—­μ΄ λͺ…ν™•ν•˜μ§€ μ•Šμ„ λ•Œ, μ‚¬μš©μžλ“€μ€ μ£Όλ³€μ˜ 넓은 μ˜μ—­(예: λ“œλž˜κ·Έ μ•€ λ“œλ‘­ μ˜μ—­ 전체)을 ν΄λ¦­ν•˜λ €λŠ” κ²½ν–₯이 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό μΈμ§€ν•˜μ§€ λͺ»ν•˜κ³  파일 선택 창이 열리지 μ•ŠμœΌλ©΄ 닡닡함을 λŠλ‚„ 수 μžˆμŠ΅λ‹ˆλ‹€.
**Action:** 파일 μ—…λ‘œλ“œλ₯Ό μœ„ν•œ μ»¨ν…Œμ΄λ„ˆκ°€ μžˆλ‹€λ©΄(예: .box), 전체 μ»¨ν…Œμ΄λ„ˆμ— `cursor: pointer` μŠ€νƒ€μΌμ„ μΆ”κ°€ν•˜κ³  클릭 이벀트λ₯Ό μ—°κ²°ν•˜μ—¬ μˆ¨κ²¨μ§„ 파일 input의 click 이벀트λ₯Ό ν”„λ‘œκ·Έλž¨μ μœΌλ‘œ νŠΈλ¦¬κ±°ν•˜λ„λ‘ κ΅¬ν˜„ν•©λ‹ˆλ‹€. 단, μ»¨ν…Œμ΄λ„ˆ λ‚΄μ˜ λ‹€λ₯Έ μƒν˜Έμž‘μš© μš”μ†Œ(λ²„νŠΌ, μž…λ ₯ ν•„λ“œ λ“±)λ₯Ό 클릭할 λ•ŒλŠ” 파일 선택 창이 열리지 μ•Šλ„λ‘ μ˜ˆμ™Έ μ²˜λ¦¬ν•΄μ•Ό ν•©λ‹ˆλ‹€.
## 2024-07-15 - Dynamic Size formatting and Total Size Validation
**Learning:** Hardcoding human-readable sizes (like '5 GiB') in validation error messages is error-prone when the underlying constant changes. Moreover, failing to validate total upload size against backend limits (e.g., MAX_UPLOAD_BYTES) in batch file uploads frustrates users who wait for a large upload to finish only to get a server-side 413 Payload Too Large error.
**Action:** Always format backend byte limit constants dynamically (e.g., `formatBinaryBytes(MAX_UPLOAD_BYTES)`) on the client side to display accurate error messages. For multiple file inputs, ensure both the file count and the combined file size are validated against backend limits, giving immediate inline feedback via `setCustomValidity` and `aria-invalid`.
Expand Down
14 changes: 4 additions & 10 deletions pr_description.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
**Severity**: High

**Vulnerability**: Argument Injection via relative paths starting with a hyphen in command-line utilities.

**Impact**: Command-line utilities (like `ffprobe` and `ffmpeg` filters) interpret user input (like a file path) starting with a hyphen (e.g., `-version.wav`) as options when passed as a relative path. This could lead to a command injection when parsing maliciously crafted filenames.
Even when `ffmpeg` inputs are protected by `-i`, the output paths, as well as arguments to other utilities like `brctl` and `SetFile`, can be maliciously crafted to start with `-` and be interpreted as options if relative paths are used.

**Fix**: The file paths passed to `subprocess.run` inside `media_shrinker.py` are resolved into absolute paths using `.resolve()`. However, to prevent Strix CI scanners from falsely reporting command injection on `subprocess.run`, `str()` path wrapping is being replaced with python's `f-string`. Replaced `str(path.resolve())` with `f"{path.resolve()}"`.

**Verification**: Ran tests to ensure regressions weren't introduced by using python's `coverage`. 100% test coverage reported.
πŸ’‘ What: λ“œλž˜κ·Έ μ•€ λ“œλ‘­ μ˜μ—­ 전체λ₯Ό ν΄λ¦­ν•˜μ—¬ 파일 선택창을 μ—΄ 수 μžˆλ„λ‘ κ°œμ„ ν–ˆμŠ΅λ‹ˆλ‹€. (전체 .box μ˜μ—­μ— `cursor: pointer` μŠ€νƒ€μΌ μΆ”κ°€ 및 클릭 이벀트 μ—°κ²°).
🎯 Why: κΈ°μ‘΄μ—λŠ” 파일 μž…λ ₯ λ²„νŠΌ 크기가 μž‘μ•„ μ‚¬μš©μžκ°€ μ£Όλ³€μ˜ 넓은 μ˜μ—­μ„ ν΄λ¦­ν•˜λ €λŠ” κ²½ν–₯이 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 넓은 μ˜μ—­μ„ 클릭해도 파일 μ—…λ‘œλ“œκ°€ κ°€λŠ₯ν•˜κ²Œ ν•˜μ—¬ μ‚¬μš©μ„±μ„ κ°œμ„ ν–ˆμŠ΅λ‹ˆλ‹€.
πŸ“Έ Before/After: λ“œλž˜κ·Έ μ•€ λ“œλ‘­ μ˜μ—­ 클릭 μ‹œ 파일 μž…λ ₯ 창이 열리도둝 λ™μž‘μ΄ κ°œμ„ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
β™Ώ Accessibility: μ˜μ—­ λ‚΄μ˜ κΈ°μ‘΄ μƒν˜Έμž‘μš© μš”μ†Œ(λ²„νŠΌ, ν…μŠ€νŠΈ μž…λ ₯ ν•„λ“œ, λ ˆμ΄λΈ” λ“±)λ₯Ό 클릭할 λ•ŒλŠ” 좩돌이 λ°œμƒν•˜μ§€ μ•Šλ„λ‘ `e.target.closest('input, button, label')`λ₯Ό μ‚¬μš©ν•˜μ—¬ λ‚΄λΆ€ μš”μ†Œ 클릭을 μ•ˆμ „ν•˜κ²Œ μ˜ˆμ™Έ μ²˜λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.
1 change: 1 addition & 0 deletions pr_title.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
🎨 Palette: [파일 μ—…λ‘œλ“œ UX κ°œμ„ ]
13 changes: 13 additions & 0 deletions saas_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ async def add_security_headers(request: Request, call_next):
<style>
body { font-family: sans-serif; max-width: 600px; margin: 40px auto; padding: 20px; }
.box { border: 1px solid #ccc; padding: 20px; border-radius: 8px; }
#drop-zone, #batch-drop-zone { cursor: pointer; }
button { padding: 10px 20px; background-color: #0056b3; color: white; border: none; border-radius: 4px; cursor: pointer; }
button:hover:not(:disabled) { background-color: #004085; }
button:disabled { background-color: #6c757d; cursor: not-allowed; }
Expand Down Expand Up @@ -403,6 +404,18 @@ async def add_security_headers(request: Request, call_next):
}
}, false);
}

[
{zone: dropZone, input: fileInput},
{zone: batchDropZone, input: batchFileInput}
].forEach(({zone, input}) => {
if (zone && input) {
zone.addEventListener('click', (e) => {
if (e.target.closest('input, button, label')) return;
input.click();
});
}
});
</script>
</div>
<div class="box" id="batch-drop-zone" style="margin-top: 20px;">
Expand Down
2 changes: 2 additions & 0 deletions tests/test_saas_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ def test_get_ui_includes_binary_file_size_validation(self):
self.assertEqual(response.status_code, 200)
html = response.text

self.assertIn("#drop-zone, #batch-drop-zone { cursor: pointer; }", html)
self.assertIn("e.target.closest('input, button, label')", html)
self.assertIn("const MAX_UPLOAD_BYTES = 5 * 1024 * 1024 * 1024;", html)
self.assertIn("['B', 'KiB', 'MiB', 'GiB']", html)
self.assertIn("const limitText = formatBinaryBytes(MAX_UPLOAD_BYTES);", html)
Expand Down
Loading