mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-07 13:23:22 +00:00
fix(engine): link watch and Link Info read within the asking caller's roots
This commit is contained in:
committed by
bflatastic
parent
40b9fa4717
commit
4d0ecb264c
@@ -1338,8 +1338,10 @@ fn placement_json(o: PlacementOptions) -> Value {
|
||||
|
||||
/// Link Info's fields of the linked file `l` (of object `id` of `st`) into `out`.
|
||||
fn file_fields(st: &crate::DocState, id: NodeId, l: &LinkInfo, out: &mut Value) {
|
||||
// Within what the caller that opened the document may read, whoever asks.
|
||||
crate::file_access::confine(st.opened_by.as_ref(), || file_fields_here(st, id, l, out));
|
||||
// A confined caller reads within its own roots; anyone else within what the caller that
|
||||
// opened the document may read (never wider than the caller asking now).
|
||||
let roots = crate::file_access::current().or_else(|| st.opened_by.clone());
|
||||
crate::file_access::confine(roots.as_ref(), || file_fields_here(st, id, l, out));
|
||||
}
|
||||
|
||||
fn file_fields_here(st: &crate::DocState, id: NodeId, l: &LinkInfo, out: &mut Value) {
|
||||
|
||||
@@ -69,6 +69,9 @@ impl Session {
|
||||
}
|
||||
let Some(st) = self.active() else { return };
|
||||
let (uid, files, doc_path) = (st.uid, crate::cmd::links::linked_groups(&st.doc), st.path.clone());
|
||||
// A confined caller's roots, else what the caller that opened the document may read (the
|
||||
// desktop frame is unconfined).
|
||||
let opened_by = st.opened_by.clone();
|
||||
if files.is_empty() {
|
||||
return;
|
||||
}
|
||||
@@ -76,7 +79,11 @@ impl Session {
|
||||
let out = slot.clone();
|
||||
let scope = crate::file_access::ScopeHandle::capture();
|
||||
let spawned = std::thread::Builder::new().name("link-watch".into()).spawn(move || {
|
||||
let stamps = scope.run(|| files.into_iter().map(|(p, ids)| (p.clone(), ids, stamp(&p, doc_path.as_deref()))).collect());
|
||||
let stamps = scope.run(|| {
|
||||
crate::file_access::confine(crate::file_access::current().or(opened_by).as_ref(), || {
|
||||
files.into_iter().map(|(p, ids)| (p.clone(), ids, stamp(&p, doc_path.as_deref()))).collect()
|
||||
})
|
||||
});
|
||||
*out.lock().unwrap_or_else(PoisonError::into_inner) = Some((uid, stamps));
|
||||
});
|
||||
if spawned.is_ok() {
|
||||
@@ -141,7 +148,8 @@ impl Session {
|
||||
let mode = if update { "automatically" } else { self.prefs.update_links.as_str() };
|
||||
match mode {
|
||||
"automatically" => {
|
||||
let r = self.execute("links.update", &json!({"ids": ids}))?;
|
||||
let roots = crate::file_access::current().or_else(|| self.active().and_then(|d| d.opened_by.clone()));
|
||||
let r = crate::file_access::confine(roots.as_ref(), || self.execute("links.update", &json!({"ids": ids})))?;
|
||||
// Not readable yet (still being written): the next look tries again.
|
||||
let unread: BTreeSet<u64> = r["missing"].as_array().map(|a| a.iter().filter_map(Value::as_u64).collect()).unwrap_or_default();
|
||||
for (path, ids) in &changed {
|
||||
|
||||
@@ -278,6 +278,24 @@ fn link_info_has_the_file_and_placement_details() {
|
||||
assert_eq!((i["status"].as_str(), i["linked"].as_bool(), i["fileName"].as_str()), (Some("embedded"), Some(false), None));
|
||||
}
|
||||
|
||||
/// Link Info reads within the opener's roots for an unconfined caller, and never past a confined
|
||||
/// caller's own roots.
|
||||
#[test]
|
||||
fn link_info_stays_within_the_asking_callers_roots() {
|
||||
let dir = Folder::new("info-roots");
|
||||
let other = Folder::new("info-other");
|
||||
let pic = dir.file("photo.png");
|
||||
write(&pic, &png(60, 30, RED));
|
||||
let mut s = session();
|
||||
let id = place(&mut s, &pic);
|
||||
let roots = |p: &std::path::Path| crate::file_access::AutomationRoots::new(&[p], &[]).unwrap().unwrap();
|
||||
s.active_mut().unwrap().opened_by = Some(roots(&dir.0));
|
||||
assert_eq!(run(&mut s, "links.info", json!({"id": id.0}))["status"], "ok");
|
||||
let narrow = roots(&other.0);
|
||||
let i = crate::file_access::confine(Some(&narrow), || run(&mut s, "links.info", json!({"id": id.0})));
|
||||
assert_ne!(i["status"], "ok", "{i}");
|
||||
}
|
||||
|
||||
/// A 600×300 pt image at the centre of the artboard, its placement options set to `options`,
|
||||
/// relinked to a 300×100 px file → the image's id and session.
|
||||
fn relinked(name: &str, options: Value) -> (Session, NodeId, Folder) {
|
||||
|
||||
Reference in New Issue
Block a user