From 88e7e21683b0bbe685d2e98683e2ed2949ca0d37 Mon Sep 17 00:00:00 2001 From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:56:34 +0530 Subject: [PATCH] fix: prefer filename from body over path in mime validation (#23810) Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> --- server/src/services/asset-media.service.spec.ts | 14 ++++++++++++-- server/src/services/asset-media.service.ts | 4 ++-- server/src/types.ts | 10 ++++++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/server/src/services/asset-media.service.spec.ts b/server/src/services/asset-media.service.spec.ts index a338c30d78..f32385b937 100644 --- a/server/src/services/asset-media.service.spec.ts +++ b/server/src/services/asset-media.service.spec.ts @@ -12,6 +12,7 @@ import { MapAsset } from 'src/dtos/asset-response.dto'; import { AssetFileType, AssetStatus, AssetType, AssetVisibility, CacheControl, JobName } from 'src/enum'; import { AuthRequest } from 'src/middleware/auth.guard'; import { AssetMediaService } from 'src/services/asset-media.service'; +import { UploadBody } from 'src/types'; import { ASSET_CHECKSUM_CONSTRAINT } from 'src/utils/database'; import { ImmichFileResponse } from 'src/utils/file'; import { assetStub } from 'test/fixtures/asset.stub'; @@ -35,10 +36,10 @@ const uploadFile = { size: 1000, }, }, - filename: (fieldName: UploadFieldName, filename: string) => { + filename: (fieldName: UploadFieldName, filename: string, body?: UploadBody) => { return { auth: authStub.admin, - body: {}, + body: body || {}, fieldName, file: { uuid: 'random-uuid', @@ -263,6 +264,15 @@ describe(AssetMediaService.name, () => { }); }); } + + it('should prefer filename from body over name from path', () => { + const pathFilename = 'invalid-file-name'; + const body = { filename: 'video.mov' }; + expect(() => sut.canUploadFile(uploadFile.filename(UploadFieldName.ASSET_DATA, pathFilename))).toThrowError( + BadRequestException, + ); + expect(sut.canUploadFile(uploadFile.filename(UploadFieldName.ASSET_DATA, pathFilename, body))).toEqual(true); + }); }); describe('getUploadFilename', () => { diff --git a/server/src/services/asset-media.service.ts b/server/src/services/asset-media.service.ts index 0747bd7b7b..8cf1ef331d 100644 --- a/server/src/services/asset-media.service.ts +++ b/server/src/services/asset-media.service.ts @@ -51,10 +51,10 @@ export class AssetMediaService extends BaseService { return { id: assetId, status: AssetMediaStatus.DUPLICATE }; } - canUploadFile({ auth, fieldName, file }: UploadRequest): true { + canUploadFile({ auth, fieldName, file, body }: UploadRequest): true { requireUploadAccess(auth); - const filename = file.originalName; + const filename = body.filename || file.originalName; switch (fieldName) { case UploadFieldName.ASSET_DATA: { diff --git a/server/src/types.ts b/server/src/types.ts index 0a2dd46d7f..afc72480e8 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -419,14 +419,16 @@ export interface UploadFile { size: number; } +export interface UploadBody { + filename?: string; + [key: string]: unknown; +} + export type UploadRequest = { auth: AuthDto | null; fieldName: UploadFieldName; file: UploadFile; - body: { - filename?: string; - [key: string]: unknown; - }; + body: UploadBody; }; export interface UploadFiles {