Harden local file storage driver path resolution (#17783)
## Summary - Normalize all file paths with `path.resolve` instead of `join` to properly handle `..` segments in file path inputs - Add `assertPathIsWithinStorage` guard on all write, delete, move, copy, and existence-check operations - Introduce `ACCESS_DENIED` exception code with i18n-ready user-friendly message - Read path already had realpath-based validation; updated its error code to `ACCESS_DENIED` for consistency ## Test plan - [x] Typecheck passes - [x] Lint passes - [x] Manual: verify file upload/download still works with valid paths - [x] Manual: verify `../` in file paths is rejected with ACCESS_DENIED Made with [Cursor](https://cursor.com) --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Etienne <etiennejouan@users.noreply.github.com>
This commit is contained in:
+1
-1
@@ -40,7 +40,7 @@ export class FileUploadService {
|
||||
mimeType: string | undefined;
|
||||
folder: string;
|
||||
}) {
|
||||
await this.fileStorage.writeFile({
|
||||
await this.fileStorage.writeFileLegacy({
|
||||
file,
|
||||
name: filename,
|
||||
mimeType,
|
||||
|
||||
+2
-2
@@ -80,7 +80,7 @@ export class FilesFieldService {
|
||||
},
|
||||
});
|
||||
|
||||
return await this.fileStorageService.writeFile_v2({
|
||||
return await this.fileStorageService.writeFile({
|
||||
sourceFile: sanitizedFile,
|
||||
resourcePath: `${fieldMetadata.universalIdentifier}/${name}`,
|
||||
mimeType,
|
||||
@@ -153,7 +153,7 @@ export class FilesFieldService {
|
||||
},
|
||||
});
|
||||
|
||||
return await this.fileStorageService.readFile_v2({
|
||||
return await this.fileStorageService.readFile({
|
||||
resourcePath: removeFileFolderFromFileEntityPath(file.path),
|
||||
fileFolder: FileFolder.FilesField,
|
||||
applicationUniversalIdentifier: application.universalIdentifier,
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('FileService', () => {
|
||||
{
|
||||
provide: FileStorageService,
|
||||
useValue: {
|
||||
copy: jest.fn(),
|
||||
copyLegacy: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -50,7 +50,7 @@ describe('FileService', () => {
|
||||
'newWorkspaceId',
|
||||
);
|
||||
|
||||
expect(fileStorageService.copy).toHaveBeenCalledWith({
|
||||
expect(fileStorageService.copyLegacy).toHaveBeenCalledWith({
|
||||
from: {
|
||||
folderPath: 'workspace-workspaceId/path/to',
|
||||
filename: 'file',
|
||||
|
||||
@@ -33,7 +33,7 @@ export class FileService {
|
||||
): Promise<Readable> {
|
||||
const workspaceFolderPath = `workspace-${workspaceId}/${folderPath}`;
|
||||
|
||||
return await this.fileStorageService.readFile({
|
||||
return await this.fileStorageService.readFileLegacy({
|
||||
filePath: `${workspaceFolderPath}/${filename}`,
|
||||
});
|
||||
}
|
||||
@@ -85,7 +85,7 @@ export class FileService {
|
||||
}) {
|
||||
const workspaceFolderPath = `workspace-${workspaceId}/${folderPath}`;
|
||||
|
||||
return await this.fileStorageService.delete({
|
||||
return await this.fileStorageService.deleteLegacy({
|
||||
folderPath: workspaceFolderPath,
|
||||
filename,
|
||||
});
|
||||
@@ -95,7 +95,7 @@ export class FileService {
|
||||
const workspaceFolderPath = `workspace-${workspaceId}`;
|
||||
|
||||
const isWorkspaceFolderFound =
|
||||
await this.fileStorageService.checkFolderExists({
|
||||
await this.fileStorageService.checkFolderExistsLegacy({
|
||||
folderPath: workspaceFolderPath,
|
||||
});
|
||||
|
||||
@@ -103,7 +103,7 @@ export class FileService {
|
||||
return;
|
||||
}
|
||||
|
||||
return await this.fileStorageService.delete({
|
||||
return await this.fileStorageService.deleteLegacy({
|
||||
folderPath: workspaceFolderPath,
|
||||
});
|
||||
}
|
||||
@@ -120,7 +120,7 @@ export class FileService {
|
||||
|
||||
const toFilename = uuidV4() + extname(fromFilename);
|
||||
|
||||
await this.fileStorageService.copy({
|
||||
await this.fileStorageService.copyLegacy({
|
||||
from: {
|
||||
folderPath: `${fromWorkspaceFolderPath}/${subFolder}`,
|
||||
filename: fromFilename,
|
||||
|
||||
Reference in New Issue
Block a user