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
@@ -429,7 +429,7 @@ export class DevSeederDataService {
|
||||
const filePath = join(sampleFilesDir, filename);
|
||||
const fileBuffer = await readFile(filePath);
|
||||
|
||||
await this.fileStorageService.writeFile({
|
||||
await this.fileStorageService.writeFileLegacy({
|
||||
file: fileBuffer,
|
||||
name: filename,
|
||||
folder: `workspace-${workspaceId}/attachment`,
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ export class CreateFrontComponentActionHandlerService extends WorkspaceMigration
|
||||
applicationUniversalIdentifier: string;
|
||||
builtComponentPath: string;
|
||||
}): Promise<void> {
|
||||
const builtExists = await this.fileStorageService.checkFileExists_v2({
|
||||
const builtExists = await this.fileStorageService.checkFileExists({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.BuiltFrontComponent,
|
||||
|
||||
+2
-2
@@ -40,13 +40,13 @@ export class CreateLogicFunctionActionHandlerService extends WorkspaceMigrationR
|
||||
const applicationUniversalIdentifier = flatApplication.universalIdentifier;
|
||||
|
||||
const [sourceExists, builtExists] = await Promise.all([
|
||||
this.fileStorageService.checkFileExists_v2({
|
||||
this.fileStorageService.checkFileExists({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: logicFunction.sourceHandlerPath,
|
||||
}),
|
||||
this.fileStorageService.checkFileExists_v2({
|
||||
this.fileStorageService.checkFileExists({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.BuiltLogicFunction,
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ export class DeleteLogicFunctionActionHandlerService extends WorkspaceMigrationR
|
||||
|
||||
const applicationUniversalIdentifier = flatApplication.universalIdentifier;
|
||||
|
||||
await this.fileStorageService.delete_v2({
|
||||
await this.fileStorageService.delete({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.BuiltLogicFunction,
|
||||
|
||||
+2
-2
@@ -73,13 +73,13 @@ export class UpdateLogicFunctionActionHandlerService extends WorkspaceMigrationR
|
||||
applicationUniversalIdentifier: string;
|
||||
}): Promise<void> {
|
||||
const [sourceExists, builtExists] = await Promise.all([
|
||||
this.fileStorageService.checkFileExists_v2({
|
||||
this.fileStorageService.checkFileExists({
|
||||
workspaceId: flatLogicFunction.workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: flatLogicFunction.sourceHandlerPath,
|
||||
}),
|
||||
this.fileStorageService.checkFileExists_v2({
|
||||
this.fileStorageService.checkFileExists({
|
||||
workspaceId: flatLogicFunction.workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.BuiltLogicFunction,
|
||||
|
||||
Reference in New Issue
Block a user