From c9d618ed2782c20dcf344836fac855526136bce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Skyler=20M=C3=A4ntysaari?= Date: Thu, 2 Feb 2023 12:36:20 +0200 Subject: [PATCH] feat(server): Some tests and specific handling for the two raw formats --- .../src/config/asset-upload.config.spec.ts | 47 ++++++++++++++----- .../immich/src/config/asset-upload.config.ts | 29 +++++++----- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/server/apps/immich/src/config/asset-upload.config.spec.ts b/server/apps/immich/src/config/asset-upload.config.spec.ts index 7649dc05e5..07730e0b99 100644 --- a/server/apps/immich/src/config/asset-upload.config.spec.ts +++ b/server/apps/immich/src/config/asset-upload.config.spec.ts @@ -55,7 +55,7 @@ describe('assetUploadOption', () => { }); it('should allow videos', async () => { - const file = { mimetype: 'image/mp4', originalname: 'test.mp4' } as any; + const file = { mimetype: 'video/mp4', originalname: 'test.mp4' } as any; fileFilter(mock.userRequest, file, callback); expect(callback).toHaveBeenCalledWith(null, true); }); @@ -66,17 +66,40 @@ describe('assetUploadOption', () => { expect(callback).toHaveBeenCalledWith(null, true); }); - // TODO: Fix it when we have a API way to get accepted mimetypes. - // it('should not allow unknown types', async () => { - // const file = { mimetype: 'application/html', originalname: 'test.html' } as any; - // const callback = jest.fn(); - // fileFilter(mock.userRequest, file, callback); - // - // expect(callback).toHaveBeenCalled(); - // const [error, accepted] = callback.mock.calls[0]; - // expect(error).toBeDefined(); - // expect(accepted).toBe(false); - // }); + it('should allow .srw unrecognized', () => { + const file = { mimetype: 'application/octet-stream', originalname: 'test.srw' } as any; + fileFilter(mock.userRequest, file, callback); + expect(callback).toHaveBeenCalledWith(null, true); + }); + + it('should allow .raf recognized', () => { + const file = { mimetype: 'image/x-fuji-raf', originalname: 'test.raf' } as any; + fileFilter(mock.userRequest, file, callback); + expect(callback).toHaveBeenCalledWith(null, true); + }); + + it('should allow .raf unrecognized', () => { + const file = { mimetype: 'application/octet-stream', originalname: 'test.raf' } as any; + fileFilter(mock.userRequest, file, callback); + expect(callback).toHaveBeenCalledWith(null, true); + }); + + it('should allow .srw recognized', () => { + const file = { mimetype: 'image/x-samsung-srw', originalname: 'test.srw' } as any; + fileFilter(mock.userRequest, file, callback); + expect(callback).toHaveBeenCalledWith(null, true); + }); + + it('should not allow unknown types', async () => { + const file = { mimetype: 'application/html', originalname: 'test.html' } as any; + const callback = jest.fn(); + fileFilter(mock.userRequest, file, callback); + + expect(callback).toHaveBeenCalled(); + const [error, accepted] = callback.mock.calls[0]; + expect(error).toBeDefined(); + expect(accepted).toBe(false); + }); }); describe('destination', () => { diff --git a/server/apps/immich/src/config/asset-upload.config.ts b/server/apps/immich/src/config/asset-upload.config.ts index 4ea27f5c0c..be1c88b619 100644 --- a/server/apps/immich/src/config/asset-upload.config.ts +++ b/server/apps/immich/src/config/asset-upload.config.ts @@ -1,11 +1,11 @@ import { APP_UPLOAD_LOCATION } from '@app/common/constants'; -import { UnauthorizedException } from '@nestjs/common'; +import { BadRequestException, Logger, UnauthorizedException } from '@nestjs/common'; import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface'; import { createHash, randomUUID } from 'crypto'; import { Request } from 'express'; import { existsSync, mkdirSync } from 'fs'; import { diskStorage, StorageEngine } from 'multer'; -import { join } from 'path'; +import { extname, join } from 'path'; import sanitize from 'sanitize-filename'; import { AuthUserDto } from '../decorators/auth-user.decorator'; import { patchFormData } from '../utils/path-form-data.util'; @@ -46,6 +46,8 @@ export function customStorage(): StorageEngine { export const multerUtils = { fileFilter, filename, destination }; +const logger = new Logger('AssetUploadConfig'); + function fileFilter(req: Request, file: any, cb: any) { if (!req.user || (req.user.isPublicUser && !req.user.isAllowUpload)) { return cb(new UnauthorizedException()); @@ -53,17 +55,18 @@ function fileFilter(req: Request, file: any, cb: any) { // TODO: Create new API endpoint for mimetypes and use that here as browser's // file mimetype is not to be trusted. // Reference about issue with it: https://stackoverflow.com/questions/26149389/mime-type-missing-for-rar-and-tar/26222177#26222177 - cb(null, true); - //if ( - // file.mimetype.match( - // /\/(jpg|jpeg|png|gif|mp4|webm|x-msvideo|quicktime|heic|heif|dng|x-adobe-dng|webp|tiff|3gpp|nef|x-nikon-nef)$/, - // ) - //) { - // cb(null, true); - //} else { - // logger.error(`Unsupported file type ${extname(file.originalname)} file MIME type ${filetype}`); - // cb(new BadRequestException(`Unsupported file type ${extname(file.originalname)}`), false); - // } + if ( + file.mimetype.match( + /\/(jpg|jpeg|png|gif|mp4|webm|x-msvideo|quicktime|heic|heif|dng|x-adobe-dng|webp|tiff|3gpp|nef|x-nikon-nef|x-fuji-raf|x-samsung-srw)$/, + ) || + (file.mimetype.match('application/octet-stream') && extname(file.originalname.toLowerCase()) == '.raf') || + (file.mimetype.match('application/octet-stream') && extname(file.originalname.toLowerCase()) == '.srw') + ) { + cb(null, true); + } else { + logger.error(`Unsupported file type ${extname(file.originalname)} file MIME type ${file.mimetype}`); + cb(new BadRequestException(`Unsupported file type ${extname(file.originalname)}`), false); + } } function destination(req: Request, file: Express.Multer.File, cb: any) {