From 77225383a4edfe0a3552fa192e3837c726950a1d Mon Sep 17 00:00:00 2001 From: arc-alex Date: Thu, 11 Dec 2025 15:35:41 +0100 Subject: [PATCH] fix: block uploading already existing file name --- apps/server/src/api-data/db/db.controller.ts | 4 ++-- .../project-service/projectServiceUtils.ts | 11 +++++++++-- apps/server/src/utils/fileManagement.ts | 19 ++++++++++++++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/apps/server/src/api-data/db/db.controller.ts b/apps/server/src/api-data/db/db.controller.ts index 5e9e4a40f..6badc9d4a 100644 --- a/apps/server/src/api-data/db/db.controller.ts +++ b/apps/server/src/api-data/db/db.controller.ts @@ -13,7 +13,7 @@ import sanitize from 'sanitize-filename'; import { doesProjectExist, handleImageUpload, - handleUploaded, + handleProjectUploaded, } from '../../services/project-service/projectServiceUtils.js'; import * as projectService from '../../services/project-service/ProjectService.js'; @@ -129,7 +129,7 @@ export async function postProjectFile(req: Request, res: Response { const newFilePath = join(publicDir.logoDir, name); await dockerSafeRename(filePath, newFilePath); - return name; } diff --git a/apps/server/src/utils/fileManagement.ts b/apps/server/src/utils/fileManagement.ts index 314ba5473..d5a036bb8 100644 --- a/apps/server/src/utils/fileManagement.ts +++ b/apps/server/src/utils/fileManagement.ts @@ -1,6 +1,8 @@ -import { existsSync, mkdirSync, PathLike } from 'fs'; +import { existsSync, mkdirSync, PathLike, constants } from 'fs'; import { readdir, copyFile, unlink } from 'fs/promises'; import { basename, join, parse } from 'path'; +import { consoleError } from './console.js'; +import { is } from './is.js'; /** * @description Creates a directory if it doesn't exist @@ -102,12 +104,23 @@ export async function copyDirectory(src: string, dest: string) { } /** + * @throws if the file already exits * workaround avoids origin errors in docker deployments * EXDEV cross-device link not permitted */ export async function dockerSafeRename(oldPath: PathLike, newPath: PathLike) { - await copyFile(oldPath, newPath); - await unlink(oldPath); + try { + await copyFile(oldPath, newPath, constants.COPYFILE_EXCL); + await unlink(oldPath); + } catch (error) { + // for securely reasons we should not let the error or fs leak server file path up the error chain + if (is.object(error) && 'code' in error && error.code === 'EEXIST') { + consoleError(`rename error: File already exists ${newPath}`); + throw new Error(`File already exists`); + } + consoleError(`rename error ${error}`); + throw new Error('Unknown file rename error'); + } } /**