fix: restrict share uploads to text files

This commit is contained in:
2026-08-16 01:21:37 +07:00 Unverified
parent 649eac1776
commit ccaaf798ff
+37 -8
View File
@@ -33,6 +33,21 @@ import {
} from "@/lib/share/limits";
const IMAGE_TYPES = "image/png,image/jpeg,image/webp,image/gif";
const TEXT_FILE_TYPES = [
"application/json",
"application/xml",
"application/yaml",
"application/toml",
"application/javascript",
"application/x-javascript",
];
const TEXT_FILE_ACCEPT = `text/*,${TEXT_FILE_TYPES.join(",")}`;
function isTextFile(file: File) {
return !file.type ||
file.type.startsWith("text/") ||
TEXT_FILE_TYPES.includes(file.type);
}
function formatBytes(bytes: number) {
if (bytes < 1024) return `${bytes} B`;
@@ -57,20 +72,33 @@ export function ShareUploadClient() {
return () => URL.revokeObjectURL(imagePreview);
}, [imagePreview]);
function showError(message: string) {
setError(message);
toast.error(message);
}
async function loadTextFile(file: File) {
setError(null);
if (!isTextFile(file)) {
showError("รองรับเฉพาะไฟล์ข้อความเท่านั้น");
return;
}
if (file.size > MAX_SHARE_TEXT_BYTES) {
setError("ไฟล์ต้องมีขนาดไม่เกิน 5 MiB");
showError("ไฟล์ต้องมีขนาดไม่เกิน 5 MiB");
return;
}
try {
const content = new TextDecoder("utf-8", { fatal: true }).decode(
await file.arrayBuffer()
);
if (content.includes("\0")) {
showError("ไฟล์ข้อความต้องไม่มีอักขระ NUL");
return;
}
setText(content);
toast.success(`เปิด ${file.name} แล้ว`);
} catch {
setError("ไฟล์ต้องเป็นข้อความ UTF-8 ที่ถูกต้อง");
showError("ไฟล์ต้องเป็นข้อความ UTF-8 ที่ถูกต้อง");
}
}
@@ -78,11 +106,11 @@ export function ShareUploadClient() {
setError(null);
if (!file) return;
if (!IMAGE_TYPES.split(",").includes(file.type)) {
setError("รูปภาพต้องเป็น PNG, JPEG, WebP หรือ GIF");
showError("รูปภาพต้องเป็น PNG, JPEG, WebP หรือ GIF");
return;
}
if (file.size > MAX_SHARE_IMAGE_BYTES) {
setError("รูปภาพต้องมีขนาดไม่เกิน 50 MiB");
showError("รูปภาพต้องมีขนาดไม่เกิน 50 MiB");
return;
}
setImage(file);
@@ -93,11 +121,11 @@ export function ShareUploadClient() {
event.preventDefault();
setError(null);
if (!text.trim()) {
setError("วางข้อความก่อนสร้างลิงก์");
showError("วางข้อความก่อนสร้างลิงก์");
return;
}
if (byteCount > MAX_SHARE_TEXT_BYTES) {
setError("ข้อความต้องมีขนาดไม่เกิน 5 MiB");
showError("ข้อความต้องมีขนาดไม่เกิน 5 MiB");
return;
}
@@ -110,12 +138,12 @@ export function ShareUploadClient() {
try {
const result = await createShareAction(formData);
if (!result.success || !result.id) {
setError(result.success ? "สร้างลิงก์ไม่สำเร็จ" : result.error);
showError(result.success ? "สร้างลิงก์ไม่สำเร็จ" : result.error);
return;
}
router.push(`/share/${result.id}`);
} catch {
setError("เชื่อมต่อเซิร์ฟเวอร์ไม่สำเร็จ ลองใหม่อีกครั้ง");
showError("เชื่อมต่อเซิร์ฟเวอร์ไม่สำเร็จ ลองใหม่อีกครั้ง");
} finally {
setPending(false);
}
@@ -196,6 +224,7 @@ export function ShareUploadClient() {
<Input
ref={textFileRef}
type="file"
accept={TEXT_FILE_ACCEPT}
className="hidden"
onChange={(event) => {
const file = event.target.files?.[0];