diff --git a/api/src/org/labkey/vfs/FileSystemLike.java b/api/src/org/labkey/vfs/FileSystemLike.java index 647d9cd7b1e..e19b0afb96f 100644 --- a/api/src/org/labkey/vfs/FileSystemLike.java +++ b/api/src/org/labkey/vfs/FileSystemLike.java @@ -222,6 +222,33 @@ static File toFile(FileLike f) return p.toFile(); } + static FileLike resolveChildWithRelativeURI(File file) + { + URI fileURI = file.toURI(); + FileLike allowedRoot = new FileSystemLike.Builder(fileURI).root(); + + // Converts an absolute URI to a relative one if it's within the base URI. + // If fileURI is outside rootURI, the result remains fileURI/unchanged. + // Examples: + // root "/a/b/c/", file "/x/y/z.txt" -> "/x/y/z.txt" + // root "/a/b/c/", file "/a/b/c/d.txt" -> "d.txt" + URI relativeURI = URIUtil.relativize(allowedRoot.toURI(), fileURI); + + if (relativeURI == null) + { + throw new IllegalArgumentException("File '" + fileURI.getPath() + "' is outside the root '" + allowedRoot.toURI().getPath() + "'"); + } + + //explicitly check whether the given file path is within the allowed root directory + if (allowedRoot.getFileSystem().isDescendant(allowedRoot, fileURI)) + { + return allowedRoot.resolveChild(relativeURI.getPath()); + } + else + { + throw new IllegalArgumentException("File '" + relativeURI.getPath() + "' is not a descendant of '" + allowedRoot.getPath() + "'"); + } + } /* More efficient version of wrap when many files may be from the same directory */ static List wrapFiles(List files)