mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 09:39:52 +00:00
MCP: another platform's absolute path is outside the read roots everywhere
Outside Windows, a path that starts with a drive (`C:`) or a `\` is read as a name in the working folder, so with the working folder inside a read root it passed the read check. ui.inspect then kept it in recorded action steps and replies did not hide it when a request sent it. The check now counts such a path as outside the read roots wherever the control channel and the library commands check a path.
This commit is contained in:
@@ -472,17 +472,10 @@ fn file_name(path: &str) -> String {
|
||||
}
|
||||
|
||||
/// May the request being served read `path` ([`crate::file_access::check_read`])? Always, without
|
||||
/// roots in force.
|
||||
/// roots in force. Another platform's absolute path ([`crate::file_access::written_elsewhere`]) is
|
||||
/// never readable under a read root.
|
||||
fn readable(path: &str) -> bool {
|
||||
crate::file_access::check_read(path).is_ok()
|
||||
}
|
||||
|
||||
/// Is `path`, under a read root, written as an absolute path of another platform: outside Windows, one
|
||||
/// that starts with a drive (`C:`) or a `\`? The file access check would read it as a name in the
|
||||
/// working folder.
|
||||
fn written_elsewhere(path: &str) -> bool {
|
||||
let foreign = path.starts_with('\\') || matches!(path.as_bytes(), [drive, b':', ..] if drive.is_ascii_alphabetic());
|
||||
!cfg!(windows) && foreign && crate::file_access::current().is_some()
|
||||
!crate::file_access::written_elsewhere(path) && crate::file_access::check_read(path).is_ok()
|
||||
}
|
||||
|
||||
/// The loaded library ids (`loaded/<path>`) whose file the request being served may not read, each
|
||||
@@ -514,7 +507,7 @@ pub fn concealed_library_ids(s: &Session, others: impl IntoIterator<Item = Strin
|
||||
(name, path)
|
||||
});
|
||||
match name {
|
||||
Some((name, path)) if name != path && (written_elsewhere(path) || !readable(path)) => hidden.push((id, name)),
|
||||
Some((name, path)) if name != path && !readable(path) => hidden.push((id, name)),
|
||||
_ => {
|
||||
taken.insert(id);
|
||||
}
|
||||
|
||||
@@ -215,6 +215,13 @@ pub fn check_read(path: &str) -> Result<(), String> {
|
||||
current().map_or(Ok(()), |r| r.check(path, Access::Read))
|
||||
}
|
||||
|
||||
/// Is `path`, under a read root, written as an absolute path of another platform: outside Windows, one
|
||||
/// that starts with a drive (`C:`) or a `\`? [`check_read`] reads it as a name in the working folder.
|
||||
pub fn written_elsewhere(path: &str) -> bool {
|
||||
let foreign = path.starts_with('\\') || matches!(path.as_bytes(), [drive, b':', ..] if drive.is_ascii_alphabetic());
|
||||
!cfg!(windows) && foreign && current().is_some()
|
||||
}
|
||||
|
||||
/// Does a command param named `key` hold a file or folder path: `path`, `paths`, `file`, `files`,
|
||||
/// `folder`, or a name ending in `Path`, `Paths`, `File`, `Files` or `Folder` (`diffPath`,
|
||||
/// `destinationFolder`)?
|
||||
|
||||
@@ -824,9 +824,10 @@ const SCRATCH_CHOICES: [&str; 2] = ["Startup", "None"];
|
||||
|
||||
/// May the request being served read `path`? Under an automation read root (a control client's
|
||||
/// request), `ui.inspect` leaves out a path outside the root, as `ui.menu.list` leaves out a recent
|
||||
/// file or a listed script outside it.
|
||||
/// file or a listed script outside it. Another platform's absolute path
|
||||
/// ([`vectorcraft_engine::file_access::written_elsewhere`]) is never readable under a read root.
|
||||
fn readable(path: &str) -> bool {
|
||||
vectorcraft_engine::file_access::check_read(path).is_ok()
|
||||
!vectorcraft_engine::file_access::written_elsewhere(path) && vectorcraft_engine::file_access::check_read(path).is_ok()
|
||||
}
|
||||
|
||||
/// Is `s` a path the request may not read, written as an absolute path (either separator, with or
|
||||
|
||||
@@ -263,6 +263,21 @@ fn a_library_saved_with_another_platforms_path_is_hidden() {
|
||||
assert_eq!(hiding.hidden, [(r"loaded/C:\Users\someone\b.svg".to_string(), "loaded/b.svg".to_string())], "{hiding:?}");
|
||||
}
|
||||
|
||||
/// Another platform's absolute path is outside the read root, also when the working folder is inside
|
||||
/// it: a request that sends one sees it by its file name.
|
||||
#[test]
|
||||
fn another_platforms_absolute_path_is_unreadable() {
|
||||
let here = std::env::current_dir().unwrap();
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[&here], &[]).unwrap();
|
||||
let path = r"C:\Users\someone\private.svg";
|
||||
let mut sent = Vec::new();
|
||||
vectorcraft_engine::file_access::confine(roots.as_ref(), || {
|
||||
assert!(!super::readable(path) && super::unreadable_absolute(path));
|
||||
super::sent_paths(&json!({"list": [path]}), &mut sent);
|
||||
});
|
||||
assert_eq!(sent, [(format!("loaded/{path}"), "loaded/private.svg".to_string())]);
|
||||
}
|
||||
|
||||
/// A hidden relative path is hidden where it stands alone or after `./`, and stays where it ends a
|
||||
/// longer path.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user