Update files

This commit is contained in:
glpshchn 2025-12-03 01:31:02 +03:00
parent 834982ef6c
commit 19b40b9160
1 changed files with 75 additions and 6 deletions

View File

@ -94,6 +94,67 @@ async function ensureBucket() {
}
}
/**
* Нормализовать имя файла для MinIO (только ASCII, транслитерация кириллицы)
* @param {string} filename - Оригинальное имя файла
* @returns {string} - Безопасное имя файла
*/
function normalizeFilename(filename) {
if (!filename) return 'file';
// Извлечь расширение
const ext = filename.split('.').pop() || '';
const nameWithoutExt = filename.substring(0, filename.lastIndexOf('.')) || filename;
// Простая транслитерация кириллицы
const translitMap = {
'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm',
'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
'ф': 'f', 'х': 'h', 'ц': 'ts', 'ч': 'ch', 'ш': 'sh', 'щ': 'sch',
'ъ': '', 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya',
'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo',
'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'Y', 'К': 'K', 'Л': 'L', 'М': 'M',
'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',
'Ф': 'F', 'Х': 'H', 'Ц': 'Ts', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sch',
'Ъ': '', 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya'
};
// Транслитерировать имя
let normalized = nameWithoutExt
.split('')
.map(char => translitMap[char] || char)
.join('');
// Убрать все не-ASCII символы (оставить только буквы, цифры, дефис, подчеркивание)
normalized = normalized.replace(/[^a-zA-Z0-9_-]/g, '_');
// Если имя пустое после нормализации, использовать 'file'
if (!normalized || normalized.trim() === '') {
normalized = 'file';
}
// Вернуть с расширением (расширение тоже нормализуем)
const safeExt = ext.replace(/[^a-zA-Z0-9]/g, '') || 'bin';
return safeExt ? `${normalized}.${safeExt}` : normalized;
}
/**
* Извлечь расширение файла безопасным способом
* @param {string} filename - Имя файла
* @returns {string} - Расширение файла
*/
function getFileExtension(filename) {
if (!filename) return 'bin';
const parts = filename.split('.');
if (parts.length < 2) return 'bin';
const ext = parts.pop().toLowerCase();
// Оставить только безопасные символы в расширении
return ext.replace(/[^a-z0-9]/g, '') || 'bin';
}
/**
* Загрузить файл в MinIO через S3 SDK
* @param {Buffer} buffer - Буфер файла
@ -108,10 +169,13 @@ async function uploadFile(buffer, filename, contentType, folder = 'posts') {
}
try {
// Генерировать уникальное имя файла
// Нормализовать имя файла для MinIO (только ASCII)
const safeFilename = normalizeFilename(filename);
const ext = getFileExtension(filename);
// Генерировать уникальное имя файла (используем только timestamp и random, без оригинального имени)
const timestamp = Date.now();
const random = Math.round(Math.random() * 1E9);
const ext = filename.split('.').pop();
const objectName = `${folder}/${timestamp}-${random}.${ext}`;
// Загрузить файл через S3 SDK
@ -119,12 +183,13 @@ async function uploadFile(buffer, filename, contentType, folder = 'posts') {
client: s3Client,
params: {
Bucket: config.minio.bucket,
Key: objectName,
Key: objectName, // Используем безопасное имя для Key
Body: buffer,
ContentType: contentType,
CacheControl: 'public, max-age=31536000', // 1 год
Metadata: {
originalname: filename,
// Сохраняем оригинальное имя в метаданных (URL-encoded для безопасности)
originalname: encodeURIComponent(filename),
uploadedAt: new Date().toISOString()
}
}
@ -137,13 +202,17 @@ async function uploadFile(buffer, filename, contentType, folder = 'posts') {
log('info', 'Файл загружен в MinIO через S3', {
objectName,
originalName: filename,
size: buffer.length,
url: fileUrl
});
return fileUrl;
} catch (error) {
log('error', 'Ошибка загрузки файла в MinIO', { error: error.message });
log('error', 'Ошибка загрузки файла в MinIO', {
error: error.message,
filename: filename
});
throw error;
}
}
@ -186,7 +255,7 @@ async function deleteFile(fileUrl) {
* @returns {Promise<number>} - Количество удаленных файлов
*/
async function deleteFiles(fileUrls) {
if (!minioClient || !fileUrls || !fileUrls.length) {
if (!s3Client || !fileUrls || !fileUrls.length) {
return 0;
}