diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts index 1bd3ed45..590717d2 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts +++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts @@ -86,17 +86,22 @@ export const useFileBrowserApp = ( Three sources, mutually exclusive by construction: the pathname for /files, a named query param for an embedded browser, and component state for an ordinary panel. - A param naming a folder OUTSIDE the jail is ignored rather than obeyed — it arrives from a URL - somebody may have edited, and `basePath` is the whole promise of an embedded browser. + ── The param is RELATIVE to the base, and that is not only for tidiness ── + + An absolute path put the account's own email in every link — `?media=/officerdev/data/ + someone@gmail.com/...` — so a URL sent to a colleague carried the owner's address with it. Relative, + the same folder is `?media=ABOUT+US`: shorter, and it says nothing about the machine or the account. + + It is also what makes the jail hold by construction rather than by comparison. The value is JOINED + to `basePath`, so there is no "outside" to check for — only `..` could climb out, and a segment of + `..` is refused outright. */ - const paramPath = pathParam ? searchParams.get(pathParam) : null; - const currentPath = urlPath - ? folderFromPathname(location.pathname) - : pathParam - ? paramPath && paramPath.startsWith(basePath) - ? paramPath - : basePath - : localPath; + const paramRelative = pathParam ? searchParams.get(pathParam) : null; + const paramPath = + paramRelative && !paramRelative.split('/').includes('..') + ? `${basePath.replace(/\/$/, '')}/${paramRelative.replace(/^\/+/, '')}` + : null; + const currentPath = urlPath ? folderFromPathname(location.pathname) : pathParam ? (paramPath ?? basePath) : localPath; const setCurrentPath = (path: string) => { // Leaving a folder closes what was open in it. A pane shows a file from the folder you were in, so // carrying it into the next one leaves the two disagreeing — the listing says one place, the pane @@ -109,8 +114,9 @@ export const useFileBrowserApp = ( const next = new URLSearchParams(withoutViewerParams(prev.toString())); // The base folder is the ABSENCE of the param, so a link to the top of an embedded browser is // the plain screen URL and nothing accumulates for having gone nowhere. - if (path === basePath) next.delete(pathParam); - else next.set(pathParam, path); + const relative = path.startsWith(basePath) ? path.slice(basePath.replace(/\/$/, '').length + 1) : ''; + if (!relative) next.delete(pathParam); + else next.set(pathParam, relative); return next; }, // Browsing folders is not navigation anybody wants twenty back-button presses of.