Skip to content
Open
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
7 changes: 3 additions & 4 deletions src/components/video-editor/SettingsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { getTestId } from "@/utils/getTestId";
import ColorPicker from "../ui/color-picker";
import { AnnotationSettingsPanel } from "./AnnotationSettingsPanel";
import { BlurSettingsPanel } from "./BlurSettingsPanel";
import { BACKGROUND_IMAGE_ACCEPT, isSupportedBackgroundImageType } from "./backgroundImageUpload";
import { CropControl } from "./CropControl";
import { KeyboardShortcutsHelp } from "./KeyboardShortcutsHelp";
import type {
Expand Down Expand Up @@ -459,9 +460,7 @@ export function SettingsPanel({

const file = files[0];

// Validate file type - only allow JPG/JPEG
const validTypes = ["image/jpeg", "image/jpg"];
if (!validTypes.includes(file.type)) {
if (!isSupportedBackgroundImageType(file.type, file.name)) {
toast.error(t("imageUpload.invalidFileType"), {
description: t("imageUpload.jpgOnly"),
});
Expand Down Expand Up @@ -1041,7 +1040,7 @@ export function SettingsPanel({
type="file"
ref={fileInputRef}
onChange={handleImageUpload}
accept=".jpg,.jpeg,image/jpeg"
accept={BACKGROUND_IMAGE_ACCEPT}
className="hidden"
/>
<Button
Expand Down
20 changes: 20 additions & 0 deletions src/components/video-editor/backgroundImageUpload.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { describe, expect, it } from "vitest";
import { isSupportedBackgroundImageType } from "./backgroundImageUpload";

describe("background image upload validation", () => {
it("accepts PNG images for custom backgrounds", () => {
expect(isSupportedBackgroundImageType("image/png", "生成画像1.png")).toBe(true);
});

it("accepts PNG images by extension when the browser does not provide a MIME type", () => {
expect(isSupportedBackgroundImageType("", "生成画像1.png")).toBe(true);
});

it("keeps rejecting non-image uploads", () => {
expect(isSupportedBackgroundImageType("text/plain", "notes.txt")).toBe(false);
});

it("does not allow extension fallback for explicit unsupported MIME types", () => {
expect(isSupportedBackgroundImageType("text/plain", "notes.png")).toBe(false);
});
});
20 changes: 20 additions & 0 deletions src/components/video-editor/backgroundImageUpload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const SUPPORTED_BACKGROUND_IMAGE_TYPES = new Set(["image/jpeg", "image/jpg", "image/png"]);
const SUPPORTED_BACKGROUND_IMAGE_EXTENSIONS = new Set([".jpg", ".jpeg", ".png"]);

export const BACKGROUND_IMAGE_ACCEPT = ".jpg,.jpeg,.png,image/jpeg,image/png";

export function isSupportedBackgroundImageType(type: string, fileName: string): boolean {
const normalizedType = type.trim().toLowerCase();
if (SUPPORTED_BACKGROUND_IMAGE_TYPES.has(normalizedType)) {
return true;
}

if (normalizedType) {
return false;
}

const lowerName = fileName.trim().toLowerCase();
return [...SUPPORTED_BACKGROUND_IMAGE_EXTENSIONS].some((extension) =>
lowerName.endsWith(extension),
Comment on lines +16 to +18
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict extension fallback to empty MIME types

The new validator accepts files by extension even when the browser reports an explicit unsupported MIME type. For example, a text/plain file named notes.png now returns true, whereas this upload path previously rejected non-image MIME types. This can pass non-image payloads into the wallpaper flow and produce broken uploads; the extension check should only run when type is empty/unknown.

Useful? React with 👍 / 👎.

);
}
2 changes: 1 addition & 1 deletion src/i18n/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
},
"imageUpload": {
"invalidFileType": "Invalid file type",
"jpgOnly": "Please upload a JPG or JPEG image file.",
"jpgOnly": "Please upload a JPG, JPEG, or PNG image file.",
"uploadSuccess": "Custom image uploaded successfully!",
"failedToUpload": "Failed to upload image",
"errorReading": "There was an error reading the file."
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/es/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
},
"imageUpload": {
"invalidFileType": "Tipo de archivo no válido",
"jpgOnly": "Por favor sube un archivo de imagen JPG o JPEG.",
"jpgOnly": "Por favor sube un archivo de imagen JPG, JPEG o PNG.",
"uploadSuccess": "¡Imagen personalizada subida exitosamente!",
"failedToUpload": "Error al subir la imagen",
"errorReading": "Hubo un error al leer el archivo."
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/fr/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
},
"imageUpload": {
"invalidFileType": "Type de fichier invalide",
"jpgOnly": "Veuillez téléverser un fichier image JPG ou JPEG.",
"jpgOnly": "Veuillez téléverser un fichier image JPG, JPEG ou PNG.",
"uploadSuccess": "Image personnalisée téléversée avec succès !",
"failedToUpload": "Échec du téléversement de l'image",
"errorReading": "Une erreur s'est produite lors de la lecture du fichier."
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/ja-JP/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
},
"imageUpload": {
"invalidFileType": "無効なファイル形式",
"jpgOnly": "JPG または JPEG 画像ファイルをアップロードしてください。",
"jpgOnly": "JPG、JPEG、または PNG 画像ファイルをアップロードしてください。",
"uploadSuccess": "カスタム画像が正常にアップロードされました!",
"failedToUpload": "画像のアップロードに失敗しました",
"errorReading": "ファイルの読み取り中にエラーが発生しました。"
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/ko-KR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
},
"imageUpload": {
"invalidFileType": "지원하지 않는 파일 형식입니다",
"jpgOnly": "JPG 또는 JPEG 이미지 파일을 업로드해 주세요.",
"jpgOnly": "JPG, JPEG 또는 PNG 이미지 파일을 업로드해 주세요.",
"uploadSuccess": "커스텀 이미지가 성공적으로 업로드되었습니다!",
"failedToUpload": "이미지 업로드에 실패했습니다",
"errorReading": "파일을 읽는 중 오류가 발생했습니다."
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/tr/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
},
"imageUpload": {
"invalidFileType": "Geçersiz dosya türü",
"jpgOnly": "Lütfen bir JPG veya JPEG görüntü dosyası yükleyin.",
"jpgOnly": "Lütfen JPG, JPEG veya PNG görüntü dosyası yükleyin.",
"uploadSuccess": "Özel görüntü başarıyla yüklendi!",
"failedToUpload": "Görüntü yüklenemedi",
"errorReading": "Dosya okunurken bir hata oluştu."
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/zh-CN/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
},
"imageUpload": {
"invalidFileType": "无效的文件类型",
"jpgOnly": "请上传 JPG 或 JPEG 格式的图片文件。",
"jpgOnly": "请上传 JPG、JPEGPNG 格式的图片文件。",
"uploadSuccess": "自定义图片上传成功!",
"failedToUpload": "上传图片失败",
"errorReading": "读取文件时出错。"
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/zh-TW/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
},
"imageUpload": {
"invalidFileType": "無效的檔案類型",
"jpgOnly": "請上傳 JPG 或 JPEG 格式的圖片檔案。",
"jpgOnly": "請上傳 JPG、JPEGPNG 格式的圖片檔案。",
"uploadSuccess": "自訂圖片上傳成功!",
"failedToUpload": "上傳圖片失敗",
"errorReading": "讀取檔案時出錯。"
Expand Down
Loading