Repository navigation
fix(file-manager): shared storage and operator links in both file managers (3.5.x) - #2549
Conversation
The shared-root mapping read KCFinder's typeURL, which resolves a relative rb_base_url against the browser script (or gives up when DOCUMENT_ROOT is a symlink), so it never named the folder: restricted managers got an empty, read-only browser on shared storage. Use the configured URL instead. A type root the site serves from outside a narrowed filemanager_path carries no file groups again instead of refusing every action. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…managers Links below a file manager root are made by the operator, never by the CMS: a shared upload folder, a plugin checked out elsewhere, images from another disk. A link whose real target exists and is new (not inside or around the ACL root, not a loop, not inside anything the walk already named or a shared type folder) is now a folder or file like any other, named by its own path, with every rule applied by that name: protected folders, file groups, the executable-name rule and the media browser type folder. Links that dangle, loop or would give a file a second name stay inert entries, and `..` past a link is refused. Both managers key a shared type folder the same way, so the classic manager can now enter it and edit its groups; the link that stands for a type folder is never deleted, renamed or unlinked. Removing any other passable link removes the link only and keeps its groups. A new fixture builds the media browser the way a web request does ($_SERVER, the working directory of browse.php, config.php), through a public_html -> evolution -> release chain, which is how the typeURL bug slipped through. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for preserving support for operator-managed shared folders. Two security boundaries still need attention before merging. Reviewed statically at c8f817c; I have not run this PR.
Please apply the safe-write-target guard to text saves before opening the file, reject final-component links consistently with other write operations, and retain the existing ACL and code-permission checks. Add a regression that invokes the actual text-save path as a user without code privileges against an existing final file link and verifies denial and unchanged target contents; also cover an ordinary allowed text file and a permitted parent-directory link.
Please keep the lexical identity for file-group ACLs while also checking the resolved filesystem target against protected real paths for every relevant read/change guard. For new write destinations, resolve and validate the nearest existing parent and the appended destination; retain the intended allowance for unrelated shared media directories. Add regression coverage for an external configured view directory reached through a passable directory link: text-save, create/upload, rename/move and delete must respect the protection for a user without code privileges, including non-PHP template extensions. Verify that an unrelated shared media directory remains usable. SokilAI |
…ough a linked file A passed link keeps its own name, which file groups are keyed by, but the protected-folder rule compared only that name. A link to a folder protected outside the ACL root (an external view path; core/, manager/ or views/ under a narrowed filemanager_path) opened it to managers without the permission. fileManagerPathIsProtected() and fileManagerPathTouchesProtected() now also match where a path lands: the real path of its nearest existing ancestor with the rest appended, so new destinations are covered too. Removing a link resolves only the folder it sits in. textsave() checked a linked file by its name while file_put_contents() followed the link, so a manager without code permissions could write PHP into the target through a text name. It now refuses a final link through fileManagerIsSafeWriteTarget(), as the classic upload over an existing name does now too (a move across file systems copies, and the copy follows a link). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, both are confirmed and fixed in 20a32a0. Both are regressions of this PR: before it, no link was ever passed, so neither alias existed. 1. Text save through a final link. The classic upload over an existing name had the same gap: 2. Protected folders reached through a link. This applies to every protected folder whose real path is outside the ACL root: an external
Tests.
Also checked over HTTP on a Deployer-style container (
Full |
Backport of #2546 (MiddleSokilAI) to 3.5.x, with the follow-up fixes and the file-manager link model from the matching 3.6 PR.
The hole on 3.5.x
When a type folder of the media browser lives in shared storage (
assets/imagesa symlink into/shared/..., orrb_base_dirset outside the release, as Deployer and many hosting setups do), the browser built file-group keys from the real path. That path lies outside the file manager root, so the key came out empty, which means public: every group restriction underassets/imageswas ignored for managers who are not administrators. Reproduced on 3.5.x: a manager outside the group lists and readsprivate/secret.jpg.The dashboard also warned "File base path seems incorrect" for any
rb_base_diroutside the base path, although shared storage is a valid setup.Changes
assets/images/...keys, refuses access when the mapping cannot be proven, and replaces the dashboard check with a real usability check.typeURL, which KCFinder resolves against the browser script (/manager/media/browser/mcpuk/assets/images, or/imageswhenDOCUMENT_ROOTis a symlink). The mapping therefore never matched, and restricted managers got an empty, read-only browser; on 3.6 this happened after fix(file-browser): preserve group permissions for shared storage #2546 was merged.config.phpnow passes the configuredrb_base_urlas_siteUploadURL, and the browser maps from it. A type folder served from outside a narrowedfilemanager_pathcarries no groups again, instead of refusing every action...past a link is refused.SharedTypeRootRequestTestbuilds the browser with the real constructor,config.php,$_SERVERand the working directory ofbrowse.php, through apublic_html -> evolution -> releasechain. The older link tests now use links that stay inert whatever the environment.The file-manager section of
AGENTS.mddescribes the link model.Verification
tests/Unit tests/Featureon PHP 8.4 (Linux): all green exceptPhpThumbCacheImagesTest, which readsng.inxand fails only in agit archivecopy (the file isexport-ignore).🤖 Generated with Claude Code