mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-12 08:52:26 +00:00
Scripts: a missing file below a link that leads nowhere is refused
A missing file below a folder link whose target does not exist got "does not exist", while one below a link to an existing outside folder was refused, so a script could tell whether the folder a link leads to exists. A missing path is now refused when the nearest entry above it that exists is a link that leads to nothing.
This commit is contained in:
@@ -478,9 +478,14 @@ impl ScriptScope {
|
||||
|
||||
/// Is the missing `path` inside a granted folder: does the nearest folder above it that exists
|
||||
/// lie inside one? On a file system where case matters, `MAIN/x` beside the granted `main` is
|
||||
/// outside, whether `MAIN` exists or not.
|
||||
/// outside, whether `MAIN` exists or not. A link above it that leads to nothing is outside too,
|
||||
/// so a script cannot tell whether the folder a link leads to exists.
|
||||
fn missing_inside(&self, path: &Path) -> bool {
|
||||
path.ancestors().skip(1).find_map(|a| std::fs::canonicalize(a).ok()).is_some_and(|real| self.roots.iter().any(|r| inside(&real, r)))
|
||||
path.ancestors()
|
||||
.skip(1)
|
||||
.find(|a| std::fs::symlink_metadata(a).is_ok())
|
||||
.and_then(|a| std::fs::canonicalize(a).ok())
|
||||
.is_some_and(|real| self.roots.iter().any(|r| inside(&real, r)))
|
||||
}
|
||||
|
||||
/// What the file or folder at `path` is, located as [`ScriptScope::locate`] locates it.
|
||||
|
||||
@@ -156,6 +156,17 @@ fn script_file_link_escape_refused() {
|
||||
// A missing file behind the link is refused like an existing one, so nothing tells them apart.
|
||||
let log = logged(&base, "var n = new File('away/nope.txt'); vc.log([n.exists, n.open('r'), n.error]);");
|
||||
assert_eq!(log, json!([[false, false, DENIED]]));
|
||||
// A folder link to an outside folder that does not exist is refused the same way, so a script
|
||||
// cannot tell whether the folder it leads to exists.
|
||||
link_folder(&base.join("gone"), &base.join("main").join("dangling"));
|
||||
let log = logged(
|
||||
&base,
|
||||
"var d = new File('dangling/nope.txt'); var e = new File('dangling/a/b.txt');\n\
|
||||
vc.log([d.exists, d.open('r'), d.error, e.open('r'), e.error]);",
|
||||
);
|
||||
assert_eq!(log, json!([[false, false, DENIED, false, DENIED]]));
|
||||
let dangling = base.join("main").join("dangling");
|
||||
std::fs::remove_dir(&dangling).or_else(|_| std::fs::remove_file(&dangling)).unwrap();
|
||||
#[cfg(unix)]
|
||||
let made = |target: &Path, link: &Path| std::os::unix::fs::symlink(target, link).is_ok();
|
||||
#[cfg(windows)]
|
||||
|
||||
+1
-1
@@ -1838,7 +1838,7 @@ VectorCraft reads files by these rules of its own:
|
||||
(`\\?\`, `\\.\`) are refused before anything is looked up: `exists` is `false`, the dates and `getFiles` give `null`,
|
||||
and `error` is `Script file access denied`. A path that leads out through a link or a junction is refused too, and
|
||||
`getFiles` leaves such an entry out. A missing file is refused the same way unless the nearest folder above it that
|
||||
exists is inside the script's folder.
|
||||
exists is inside the script's folder. It is also refused when a link above it leads to a folder that does not exist.
|
||||
- `open` reads the whole file. A file larger than 8 MiB is refused from its size before any of it is read, with
|
||||
`Script file exceeds 8 MiB`, and a run that opens more than 32 MiB in all ends with an error. A run has at most 256
|
||||
files open at once; another `open` returns `false` with `Script has 256 files open` until one is closed.
|
||||
|
||||
Reference in New Issue
Block a user