generated from VLADIMIR/template
fix
This commit is contained in:
@@ -13,20 +13,15 @@ import (
|
||||
"evening_detective_server/internal/modules/string_tools"
|
||||
)
|
||||
|
||||
// Ошибки валидации загружаемого файла. Маппятся в gRPC-статусы в app-слое:
|
||||
// ErrFileTooLarge → ResourceExhausted, остальные → InvalidArgument.
|
||||
var (
|
||||
ErrEmptyName = errors.New("пустое имя файла")
|
||||
ErrEmptyData = errors.New("пустые данные файла")
|
||||
ErrInvalidExtension = errors.New("недопустимое расширение файла (разрешены pdf, jpg, jpeg, png, gif, webp, mp3, ogg, wav, mp4, webm)")
|
||||
ErrInvalidContentType = errors.New("содержимое файла не соответствует разрешённым типам (pdf, изображения, аудио или видео)")
|
||||
ErrFileTooLarge = errors.New("файл слишком большой")
|
||||
// ErrFileNotFound — файл отсутствует в хранилище.
|
||||
ErrFileNotFound = errors.New("файл не найден")
|
||||
ErrFileNotFound = errors.New("файл не найден")
|
||||
)
|
||||
|
||||
// allowedExtensions — расширения, разрешённые для загрузки: PDF, изображения
|
||||
// и аудио/видео (введение и закрывашка загружаются тем же эндпоинтом).
|
||||
var allowedExtensions = map[string]struct{}{
|
||||
".pdf": {},
|
||||
".jpg": {},
|
||||
@@ -58,12 +53,6 @@ func NewFileService(
|
||||
}
|
||||
}
|
||||
|
||||
// UploadFile сохраняет файл в хранилище под уникальным именем и возвращает
|
||||
// сохранённое имя и категорию файла (image|pdf|audio|video).
|
||||
//
|
||||
// Порядок проверок: имя/данные → расширение → base → размер → содержимое.
|
||||
// Проверка размера — defense-in-depth: фактический лимит запроса
|
||||
// устанавливается на HTTP-слое (MaxBytesReader) и gRPC-лимитами.
|
||||
func (s *FileService) UploadFile(
|
||||
ctx context.Context,
|
||||
filename string,
|
||||
@@ -86,8 +75,6 @@ func (s *FileService) UploadFile(
|
||||
return "", "", ErrEmptyName
|
||||
}
|
||||
|
||||
// Транслитерация может обнулить base (например, «!!!.pdf»): хранимое
|
||||
// имя без base недопустимо — проверяем до размера и содержимого.
|
||||
transliterated := string_tools.Transliterate(base)
|
||||
if transliterated == "" {
|
||||
return "", "", ErrEmptyName
|
||||
@@ -97,8 +84,6 @@ func (s *FileService) UploadFile(
|
||||
return "", "", fmt.Errorf("%w (лимит %d МБ)", ErrFileTooLarge, s.maxFileSize>>20)
|
||||
}
|
||||
|
||||
// Категория по содержимому (сырой sniff): text/* и octet-stream не
|
||||
// проходят вообще, расширение должно соответствовать категории.
|
||||
sniffed := http.DetectContentType(data)
|
||||
if ext == ".mp3" && isMP3(data) {
|
||||
sniffed = "audio/mpeg"
|
||||
@@ -124,16 +109,12 @@ func (s *FileService) UploadFile(
|
||||
return storedName, fileType, nil
|
||||
}
|
||||
|
||||
// isMP3 распознаёт MP3 без необязательного ID3-тега по заголовку MPEG-фрейма.
|
||||
func isMP3(data []byte) bool {
|
||||
return len(data) >= 4 && data[0] == 0xff && data[1]&0xe0 == 0xe0 &&
|
||||
data[1]&0x18 != 0x08 && data[1]&0x06 != 0 &&
|
||||
data[2]&0xf0 != 0 && data[2]&0xf0 != 0xf0 && data[2]&0x0c != 0x0c
|
||||
}
|
||||
|
||||
// contentTypeCategory возвращает категорию по sniffed-типу:
|
||||
// application/pdf → pdf; image/* → image; audio/* и application/ogg → audio;
|
||||
// всё остальное (text/*, application/octet-stream и пр.) → "".
|
||||
func contentTypeCategory(sniffed string) string {
|
||||
switch {
|
||||
case sniffed == "application/pdf":
|
||||
|
||||
Reference in New Issue
Block a user