matrix-mcp: report the sanitized file name that download_file wrote
This commit is contained in:
parent
eb4ce56100
commit
262505e16a
1 changed files with 24 additions and 7 deletions
|
|
@ -1128,6 +1128,17 @@ fn media_parts(
|
||||||
Some((source.clone(), name.to_owned(), caption.map(str::to_owned)))
|
Some((source.clone(), name.to_owned(), caption.map(str::to_owned)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The last path segment of a sender-supplied attachment name, so it cannot
|
||||||
|
/// point outside the temp dir; `matrix-attachment` when nothing usable is
|
||||||
|
/// left.
|
||||||
|
fn safe_file_name(name: &str) -> &str {
|
||||||
|
std::path::Path::new(name)
|
||||||
|
.file_name()
|
||||||
|
.and_then(|n| n.to_str())
|
||||||
|
.filter(|n| !n.is_empty())
|
||||||
|
.unwrap_or("matrix-attachment")
|
||||||
|
}
|
||||||
|
|
||||||
/// Download the media attachment carried by `event_id` in `room` and
|
/// Download the media attachment carried by `event_id` in `room` and
|
||||||
/// write it to a local file, returning the path. Resolves the event,
|
/// write it to a local file, returning the path. Resolves the event,
|
||||||
/// extracts the `MediaSource` from its `m.file` / `m.image` / `m.audio`
|
/// extracts the `MediaSource` from its `m.file` / `m.image` / `m.audio`
|
||||||
|
|
@ -1180,15 +1191,11 @@ pub async fn download_file(
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => return DaemonResponse::error(format!("download media for {eid}: {e}")),
|
Err(e) => return DaemonResponse::error(format!("download media for {eid}: {e}")),
|
||||||
};
|
};
|
||||||
|
let filename = safe_file_name(&filename);
|
||||||
let dest = if let Some(p) = dest_path {
|
let dest = if let Some(p) = dest_path {
|
||||||
std::path::PathBuf::from(p)
|
std::path::PathBuf::from(p)
|
||||||
} else {
|
} else {
|
||||||
let name = std::path::Path::new(&filename)
|
std::env::temp_dir().join(filename)
|
||||||
.file_name()
|
|
||||||
.and_then(|n| n.to_str())
|
|
||||||
.filter(|n| !n.is_empty())
|
|
||||||
.unwrap_or("matrix-attachment");
|
|
||||||
std::env::temp_dir().join(name)
|
|
||||||
};
|
};
|
||||||
if let Err(e) = tokio::fs::write(&dest, &bytes).await {
|
if let Err(e) = tokio::fs::write(&dest, &bytes).await {
|
||||||
return DaemonResponse::error(format!("write {}: {e}", dest.display()));
|
return DaemonResponse::error(format!("write {}: {e}", dest.display()));
|
||||||
|
|
@ -1315,7 +1322,8 @@ mod utd_body_tests {
|
||||||
mod unread_tests {
|
mod unread_tests {
|
||||||
use super::{
|
use super::{
|
||||||
ParsedEvent, TimelineEvent, attachment_marker, collapse_edits, extract_body_sync,
|
ParsedEvent, TimelineEvent, attachment_marker, collapse_edits, extract_body_sync,
|
||||||
extract_in_reply_to, is_intentional, media_parts, replacement_of, unread_verdict,
|
extract_in_reply_to, is_intentional, media_parts, replacement_of, safe_file_name,
|
||||||
|
unread_verdict,
|
||||||
};
|
};
|
||||||
use matrix_sdk::ruma::events::AnySyncTimelineEvent;
|
use matrix_sdk::ruma::events::AnySyncTimelineEvent;
|
||||||
use matrix_sdk::ruma::events::room::message::MessageType;
|
use matrix_sdk::ruma::events::room::message::MessageType;
|
||||||
|
|
@ -1705,6 +1713,15 @@ mod unread_tests {
|
||||||
assert!(media_parts(&msgtype(&json!({"msgtype": "m.text", "body": "x"}))).is_none());
|
assert!(media_parts(&msgtype(&json!({"msgtype": "m.text", "body": "x"}))).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn an_attachment_name_is_reduced_to_its_last_segment() {
|
||||||
|
assert_eq!(safe_file_name("a.png"), "a.png");
|
||||||
|
assert_eq!(safe_file_name("../../etc/x.png"), "x.png");
|
||||||
|
assert_eq!(safe_file_name("dir/"), "dir");
|
||||||
|
assert_eq!(safe_file_name(""), "matrix-attachment");
|
||||||
|
assert_eq!(safe_file_name(".."), "matrix-attachment");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn attachments_render_as_typed_markers_and_text_as_itself() {
|
fn attachments_render_as_typed_markers_and_text_as_itself() {
|
||||||
let marker = |kind: &str, extra: serde_json::Value| {
|
let marker = |kind: &str, extra: serde_json::Value| {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue