Skip to content

Commit a6ab404

Browse files
fix(files): resolve escaped folder lookups
1 parent 2461d10 commit a6ab404

2 files changed

Lines changed: 35 additions & 30 deletions

File tree

apps/sim/lib/uploads/contexts/workspace/workspace-file-manager.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,18 @@ describe('workspace file reference normalization', () => {
7575
archiveFile
7676
)
7777
})
78+
79+
it('resolves an encoded slash within one folder segment', () => {
80+
const legalFile: WorkspaceFileRecord = {
81+
...makeFileRecord(),
82+
id: 'file-legal',
83+
name: 'contract.pdf',
84+
folderId: 'folder-legal',
85+
folderPath: 'Finance\\/Legal',
86+
}
87+
88+
expect(findWorkspaceFileRecord([legalFile], 'files/Finance%2FLegal/contract.pdf/content')).toBe(
89+
legalFile
90+
)
91+
})
7892
})

apps/sim/lib/uploads/contexts/workspace/workspace-file-manager.ts

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,10 @@ export async function queryWorkspaceFiles(
12841284
* Files are addressed by their sanitized canonical path; id-based VFS paths are not supported.
12851285
*/
12861286
export function normalizeWorkspaceFileReference(fileReference: string): string {
1287+
return normalizeWorkspaceFileReferenceSegments(fileReference).join('/')
1288+
}
1289+
1290+
function normalizeWorkspaceFileReferenceSegments(fileReference: string): string[] {
12871291
const trimmed = fileReference.trim().replace(/^\/+/, '')
12881292
const withoutDeletedPrefix = trimmed.startsWith('recently-deleted/')
12891293
? trimmed.slice('recently-deleted/'.length)
@@ -1292,15 +1296,15 @@ export function normalizeWorkspaceFileReference(fileReference: string): string {
12921296
if (withoutDeletedPrefix.startsWith('files/')) {
12931297
const withoutPrefix = withoutDeletedPrefix.slice('files/'.length)
12941298
if (withoutPrefix.endsWith('/meta.json')) {
1295-
return decodeVfsPathSegments(withoutPrefix.slice(0, -'/meta.json'.length)).join('/')
1299+
return decodeVfsPathSegments(withoutPrefix.slice(0, -'/meta.json'.length))
12961300
}
12971301
if (withoutPrefix.endsWith('/content')) {
1298-
return decodeVfsPathSegments(withoutPrefix.slice(0, -'/content'.length)).join('/')
1302+
return decodeVfsPathSegments(withoutPrefix.slice(0, -'/content'.length))
12991303
}
1300-
return decodeVfsPathSegments(withoutPrefix).join('/')
1304+
return decodeVfsPathSegments(withoutPrefix)
13011305
}
13021306

1303-
return decodeVfsPathSegments(withoutDeletedPrefix).join('/')
1307+
return decodeVfsPathSegments(withoutDeletedPrefix)
13041308
}
13051309

13061310
/**
@@ -1325,40 +1329,29 @@ export function findWorkspaceFileRecord(
13251329
return exactIdMatch
13261330
}
13271331

1328-
const normalizedReference = normalizeWorkspaceFileReference(fileReference)
1332+
const referenceSegments = normalizeWorkspaceFileReferenceSegments(fileReference)
1333+
const normalizedReference = referenceSegments.join('/')
13291334
const normalizedIdMatch = files.find((file) => file.id === normalizedReference)
13301335
if (normalizedIdMatch) {
13311336
return normalizedIdMatch
13321337
}
13331338

1334-
const segmentKey = normalizedReference
1335-
.split('/')
1336-
.map((segment) => normalizeVfsSegment(segment))
1337-
.join('/')
1338-
const normalizedPathMatch = files.find((file) => {
1339-
const folderPath = file.folderPath
1340-
?.split('/')
1341-
.map((segment) => normalizeVfsSegment(segment))
1342-
.join('/')
1343-
const fullPath = folderPath
1344-
? `${folderPath}/${normalizeVfsSegment(file.name)}`
1345-
: normalizeVfsSegment(file.name)
1346-
return fullPath === segmentKey
1347-
})
1339+
const segmentKey = referenceSegments.map(normalizeVfsSegment).join('/')
1340+
const normalizedPathMatch = files.find(
1341+
(file) =>
1342+
canonicalWorkspaceFilePath({ folderPath: file.folderPath, name: file.name }).slice(
1343+
'files/'.length
1344+
) === segmentKey
1345+
)
13481346
if (normalizedPathMatch) return normalizedPathMatch
13491347

13501348
return files.find((file) => normalizeVfsSegment(file.name) === segmentKey) ?? null
13511349
}
13521350

13531351
async function getWorkspaceFileByExactReference(
13541352
workspaceId: string,
1355-
fileReference: string
1353+
segments: string[]
13561354
): Promise<WorkspaceFileRecord | null> {
1357-
const segments = fileReference
1358-
.split('/')
1359-
.map((segment) => segment.trim())
1360-
.filter(Boolean)
1361-
13621355
if (segments.length === 0) return null
13631356
if (segments.length === 1) {
13641357
return getWorkspaceFileByName(workspaceId, segments[0], { folderId: null })
@@ -1375,16 +1368,14 @@ export async function resolveWorkspaceFileReference(
13751368
workspaceId: string,
13761369
fileReference: string
13771370
): Promise<WorkspaceFileRecord | null> {
1378-
const normalizedReference = normalizeWorkspaceFileReference(fileReference)
1371+
const referenceSegments = normalizeWorkspaceFileReferenceSegments(fileReference)
1372+
const normalizedReference = referenceSegments.join('/')
13791373
if (normalizedReference.startsWith('wf_')) {
13801374
const file = await getWorkspaceFile(workspaceId, normalizedReference, { throwOnError: true })
13811375
if (file) return file
13821376
}
13831377

1384-
const exactReferenceFile = await getWorkspaceFileByExactReference(
1385-
workspaceId,
1386-
normalizedReference
1387-
)
1378+
const exactReferenceFile = await getWorkspaceFileByExactReference(workspaceId, referenceSegments)
13881379
if (exactReferenceFile) return exactReferenceFile
13891380

13901381
const files = await listWorkspaceFiles(workspaceId)

0 commit comments

Comments
 (0)