mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 15:25:16 +00:00
MCP: a screenshot's reply hides library paths outside the read roots
The reply is sent after the request was handled, and now hides what any other reply hides.
This commit is contained in:
@@ -157,9 +157,12 @@ impl VectorcraftApp {
|
||||
let pending = self.pending_screenshots.remove(index);
|
||||
self.screenshot_reserved = self.screenshot_reserved.saturating_sub(pending.reserved_bytes);
|
||||
let roots = self.automation_roots.clone();
|
||||
let _ = pending
|
||||
.reply
|
||||
.send(file_access::confine(roots.as_ref(), || control::save_screenshot(self, &image, pending.path.as_deref(), pending.data)));
|
||||
let reply = file_access::confine(roots.as_ref(), || {
|
||||
let mut reply = control::save_screenshot(self, &image, pending.path.as_deref(), pending.data);
|
||||
control::hide_in_deferred_reply(self, &mut reply, &json!({"path": pending.path}));
|
||||
reply
|
||||
});
|
||||
let _ = pending.reply.send(reply);
|
||||
}
|
||||
Err(e) => {
|
||||
let error = format!("the screenshot could not be used: {e}");
|
||||
|
||||
@@ -1027,8 +1027,9 @@ const DOCKING_ACTION: &str = "action";
|
||||
/// errors included, an error from a panic too: the libraries hidden before it ran and after it. The
|
||||
/// error of a failed request also hides the paths outside the read root that the request sent
|
||||
/// ([`sent_paths`]). A reply with no `/`, `\` or `%` in it is not searched, since every hidden path
|
||||
/// holds a separator, written or escaped. A deferred reply (a screenshot, a `ui.pointer` reply sent
|
||||
/// after the tool's edit) holds no library id or path.
|
||||
/// holds a separator, written or escaped. A screenshot's reply is hidden when it is sent
|
||||
/// ([`hide_in_deferred_reply`]); a `ui.pointer` reply sent after the tool's edit holds no library id
|
||||
/// or path.
|
||||
pub fn handle(app: &mut VectorcraftApp, ctx: &egui::Context, req: &ControlRequest) -> Outcome {
|
||||
if vectorcraft_engine::file_access::current().is_none() {
|
||||
return dispatch(app, ctx, req);
|
||||
@@ -1056,18 +1057,33 @@ pub fn handle(app: &mut VectorcraftApp, ctx: &egui::Context, req: &ControlReques
|
||||
}
|
||||
};
|
||||
let Outcome::Done(mut reply) = outcome else { return outcome };
|
||||
if !holds_a_separator(&reply) {
|
||||
return Outcome::Done(reply);
|
||||
hide_in_reply(app, &mut reply, &req.params, before);
|
||||
Outcome::Done(reply)
|
||||
}
|
||||
|
||||
/// Hides in `reply` the libraries hidden now and in `before`, and for a failed request the paths
|
||||
/// outside the read root that `sent`, the request's params, holds ([`handle`]).
|
||||
fn hide_in_reply(app: &VectorcraftApp, reply: &mut Value, sent: &Value, before: Hiding) {
|
||||
if !holds_a_separator(reply) {
|
||||
return;
|
||||
}
|
||||
let mut hiding = unreadable_library_ids(app);
|
||||
hiding.merge(before);
|
||||
if reply.get("ok").and_then(Value::as_bool) == Some(false) {
|
||||
let mut sent = Vec::new();
|
||||
sent_paths(&req.params, &mut sent);
|
||||
hiding.set_hidden(sent, cfg!(windows));
|
||||
let mut paths = Vec::new();
|
||||
sent_paths(sent, &mut paths);
|
||||
hiding.set_hidden(paths, cfg!(windows));
|
||||
}
|
||||
hide_library_ids(reply, &hiding);
|
||||
}
|
||||
|
||||
/// Hides in a reply sent after its request was handled (a screenshot's) what [`handle`] hides in a
|
||||
/// reply, with `sent` as the request's params. Without a read root in force it leaves the reply as
|
||||
/// it is.
|
||||
pub(crate) fn hide_in_deferred_reply(app: &VectorcraftApp, reply: &mut Value, sent: &Value) {
|
||||
if vectorcraft_engine::file_access::current().is_some() {
|
||||
hide_in_reply(app, reply, sent, Hiding::default());
|
||||
}
|
||||
hide_library_ids(&mut reply, &hiding);
|
||||
Outcome::Done(reply)
|
||||
}
|
||||
|
||||
/// The control methods that send synthetic input.
|
||||
|
||||
@@ -704,6 +704,26 @@ fn an_error_hides_a_sent_path_whether_or_not_a_library_was_loaded_from_it() {
|
||||
let _ = std::fs::remove_dir_all(base);
|
||||
}
|
||||
|
||||
/// A screenshot's reply, sent after its request was handled, hides a hidden library's path, and in an
|
||||
/// error the path outside the read root that the request sent.
|
||||
#[test]
|
||||
fn a_screenshot_reply_hides_paths_like_any_reply() {
|
||||
let (mut app, _tx, base) = confined("deferred-reply");
|
||||
let path = s(base.join("outside/b.svg"));
|
||||
app.ui.color_guide_limit = format!("loaded/{path}");
|
||||
let sent = s(base.join("outside/shot.png"));
|
||||
let roots = AutomationRoots::new(&[&base.join("in")], &[&base.join("out")]).unwrap();
|
||||
let mut done = json!({"ok": true, "result": {"note": format!("from {path}")}});
|
||||
let mut failed = json!({"ok": false, "error": format!("could not write {sent}")});
|
||||
vectorcraft_engine::file_access::confine(roots.as_ref(), || {
|
||||
crate::control::hide_in_deferred_reply(&app, &mut done, &json!({"path": sent}));
|
||||
crate::control::hide_in_deferred_reply(&app, &mut failed, &json!({"path": sent}));
|
||||
});
|
||||
assert_eq!(done["result"]["note"], "from b.svg", "{done}");
|
||||
assert_eq!(failed["error"], "could not write shot.png", "{failed}");
|
||||
let _ = std::fs::remove_dir_all(base);
|
||||
}
|
||||
|
||||
/// A reply whose only trace of a hidden library's path is a `file:` URL with every separator escaped
|
||||
/// shows the file name.
|
||||
#[test]
|
||||
|
||||
+2
-2
@@ -154,8 +154,8 @@ the suite) keep the agent to the folders you give it:
|
||||
reopens its panel), and the reply to such a request shows that id and file name wherever the library's id or path
|
||||
appears, an error included. Every reply under the read roots shows a hidden library's id as the id shown and its
|
||||
path as the file name in every string and key, the status text (`ui.status`), dialogs, the command palette query
|
||||
(`ui.palette_query`), a script's report (`scriptReport`) and the error from an internal fault included, for the
|
||||
libraries hidden before the request ran and after it. The path is also matched with `%XX` escapes as a `file:`
|
||||
(`ui.palette_query`), a script's report (`scriptReport`), a screenshot's reply and the error from an internal
|
||||
fault included, for the libraries hidden before the request ran and after it. The path is also matched with `%XX` escapes as a `file:`
|
||||
URL writes it, and on Windows in any case of its letters. A hidden id or path stays only where it begins
|
||||
another loaded library's whole id with no `.` or `..` part, so a readable library's id that begins with a hidden one stays. The error of a failed request also shows a path outside the
|
||||
read roots that the request sent by its file name, whether or not a library was loaded from it, so that the
|
||||
|
||||
Reference in New Issue
Block a user