import path from 'node:path'; import { resolveUserWorkspaceRoot, resolveZoneFilePath } from './user-space.mjs'; export const WORKSPACE_STORAGE_PREFIX = 'workspace://'; export function buildWorkspaceStorageKey(userId, categoryCode, relativeFilename) { const category = String(categoryCode ?? '').trim(); const relativePath = String(relativeFilename ?? '').replace(/\\/g, '/').replace(/^\/+/, ''); if (!userId || !category || !relativePath) { throw new Error('invalid workspace storage key parts'); } if (relativePath.split('/').some((part) => part === '..' || part === '.')) { throw new Error('invalid workspace relative path'); } return `${WORKSPACE_STORAGE_PREFIX}${userId}/${category}/${relativePath}`; } export function isWorkspaceStorageKey(storageKey) { return String(storageKey ?? '').startsWith(WORKSPACE_STORAGE_PREFIX); } export function resolveWorkspaceStoragePath(h5Root, storageKey) { if (!h5Root || !isWorkspaceStorageKey(storageKey)) return null; const rest = storageKey.slice(WORKSPACE_STORAGE_PREFIX.length); const slash = rest.indexOf('/'); if (slash <= 0) return null; const userId = rest.slice(0, slash); const remainder = rest.slice(slash + 1); const slash2 = remainder.indexOf('/'); if (slash2 <= 0) return null; const categoryCode = remainder.slice(0, slash2); const relativeFilename = remainder.slice(slash2 + 1); if (!relativeFilename) return null; const workspaceRoot = resolveUserWorkspaceRoot(h5Root, { id: userId }); const resolved = path.resolve(resolveZoneFilePath(workspaceRoot, categoryCode, relativeFilename)); const zoneRoot = path.resolve(resolveZoneFilePath(workspaceRoot, categoryCode, '')); if (resolved !== zoneRoot && !resolved.startsWith(`${zoneRoot}${path.sep}`)) { return null; } return resolved; }