diff --git a/backend/src/utils/filename.ts b/backend/src/utils/filename.ts new file mode 100644 index 0000000..069c401 --- /dev/null +++ b/backend/src/utils/filename.ts @@ -0,0 +1,53 @@ +const UMLAUT_REPLACEMENTS: Record = { + Ae: "Ae", + Oe: "Oe", + Ue: "Ue", + ae: "ae", + oe: "oe", + ue: "ue", + ss: "ss", + Ä: "Ae", + Ö: "Oe", + Ü: "Ue", + ä: "ae", + ö: "oe", + ü: "ue", + ß: "ss" +} + +function replaceGermanCharacters(value: string) { + return value.replace(/[ÄÖÜäöüß]/g, (char) => UMLAUT_REPLACEMENTS[char] || char) +} + +function sanitizeFileNamePart(value: string) { + return value + .normalize("NFKD") + .replace(/[\u0300-\u036f]/g, "") + .replace(/[^A-Za-z0-9._-]+/g, "-") + .replace(/-+/g, "-") + .replace(/[._-]{2,}/g, (match) => match[0]) + .replace(/^[._-]+|[._-]+$/g, "") +} + +export function sanitizeFilename(filename?: string | null, fallback = "file") { + const rawName = (filename || "").trim() + + if (!rawName) { + return fallback + } + + const normalized = replaceGermanCharacters(rawName) + .replace(/[\u0000-\u001f\u007f]/g, "") + .replace(/[\\/]/g, "-") + + const lastDotIndex = normalized.lastIndexOf(".") + const hasExtension = lastDotIndex > 0 && lastDotIndex < normalized.length - 1 + + const basename = hasExtension ? normalized.slice(0, lastDotIndex) : normalized + const extension = hasExtension ? normalized.slice(lastDotIndex + 1) : "" + + const safeBasename = sanitizeFileNamePart(basename) || fallback + const safeExtension = extension ? sanitizeFileNamePart(extension).toLowerCase() : "" + + return safeExtension ? `${safeBasename}.${safeExtension}` : safeBasename +}