Skip to content

Commit 53476a2

Browse files
committed
preserve thread target validation order
Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
1 parent 9e6ee81 commit 53476a2

1 file changed

Lines changed: 55 additions & 11 deletions

File tree

crates/buzz-cli/src/commands/messages.rs

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -393,16 +393,15 @@ pub async fn cmd_get_messages(
393393
}
394394

395395
pub fn resolve_thread_target(
396-
channel_id: &str,
396+
expected_channel_id: Uuid,
397397
event_id: &str,
398398
expected_root_id: Option<&str>,
399399
selected_event: &serde_json::Value,
400400
) -> Result<String, CliError> {
401-
let expected_channel_id = parse_uuid(channel_id)?;
402401
let actual_channel_id = channel_id_from_event(event_id, selected_event)?;
403402
if actual_channel_id != expected_channel_id {
404403
return Err(CliError::Usage(format!(
405-
"event {event_id} does not belong to channel {channel_id}"
404+
"event {event_id} does not belong to channel {expected_channel_id}"
406405
)));
407406
}
408407
let root_event_id = thread_ref_from_event(event_id, selected_event)?
@@ -425,10 +424,15 @@ pub async fn cmd_get_thread(
425424
depth_limit: Option<u32>,
426425
format: &crate::OutputFormat,
427426
) -> Result<(), CliError> {
427+
let expected_channel_id = parse_uuid(channel_id)?;
428428
validate_hex64(event_id)?;
429429
let selected_event = fetch_event(client, event_id).await?;
430-
let root_event_id =
431-
resolve_thread_target(channel_id, event_id, expected_root_id, &selected_event)?;
430+
let root_event_id = resolve_thread_target(
431+
expected_channel_id,
432+
event_id,
433+
expected_root_id,
434+
&selected_event,
435+
)?;
432436
let limit = limit.unwrap_or(100).min(500);
433437

434438
let mut reply_filter = serde_json::json!({
@@ -1050,13 +1054,15 @@ pub async fn dispatch(
10501054
#[cfg(test)]
10511055
mod tests {
10521056
use super::{
1053-
channel_id_from_event, event_mention_pubkeys, find_root_from_tags, match_profiles_by_name,
1054-
merge_message_mentions, missing_members, normalize_explicit_mentions, parse_member_pubkeys,
1055-
resolve_names_to_pubkeys, resolve_thread_target, thread_ref_from_event,
1057+
channel_id_from_event, cmd_get_thread, event_mention_pubkeys, find_root_from_tags,
1058+
match_profiles_by_name, merge_message_mentions, missing_members,
1059+
normalize_explicit_mentions, parse_member_pubkeys, resolve_names_to_pubkeys,
1060+
resolve_thread_target, thread_ref_from_event, BuzzClient, CliError, Uuid,
10561061
};
10571062
use buzz_sdk::mentions::{
10581063
extract_at_mentions_with_known, extract_at_names, match_names_to_profiles, MentionProfile,
10591064
};
1065+
use nostr::Keys;
10601066
use serde_json::json;
10611067

10621068
const ID_A: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
@@ -1069,6 +1075,26 @@ mod tests {
10691075
const PK_VALID_B: &str = "c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05";
10701076
const PK_VALID_C: &str = "f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68";
10711077

1078+
#[tokio::test]
1079+
async fn malformed_channel_is_rejected_before_thread_fetch() {
1080+
let client =
1081+
BuzzClient::new("http://127.0.0.1:1".into(), Keys::generate(), None, None).unwrap();
1082+
let error = cmd_get_thread(
1083+
&client,
1084+
"not-a-uuid",
1085+
ID_A,
1086+
None,
1087+
None,
1088+
None,
1089+
&crate::OutputFormat::Json,
1090+
)
1091+
.await
1092+
.unwrap_err();
1093+
1094+
assert!(matches!(error, CliError::Usage(_)));
1095+
assert!(error.to_string().contains("invalid UUID"));
1096+
}
1097+
10721098
#[test]
10731099
fn selected_event_derives_authoritative_channel_and_root() {
10741100
let channel = "123e4567-e89b-12d3-a456-426614174000";
@@ -1109,10 +1135,28 @@ mod tests {
11091135
"tags": [["h", channel], ["e", ID_A, "", "root"]]
11101136
});
11111137

1112-
assert!(resolve_thread_target(other_channel, ID_B, Some(ID_A), &selected).is_err());
1113-
assert!(resolve_thread_target(channel, ID_B, Some(ID_B), &selected).is_err());
1138+
assert!(resolve_thread_target(
1139+
Uuid::parse_str(other_channel).unwrap(),
1140+
ID_B,
1141+
Some(ID_A),
1142+
&selected,
1143+
)
1144+
.is_err());
1145+
assert!(resolve_thread_target(
1146+
Uuid::parse_str(channel).unwrap(),
1147+
ID_B,
1148+
Some(ID_B),
1149+
&selected,
1150+
)
1151+
.is_err());
11141152
assert_eq!(
1115-
resolve_thread_target(channel, ID_B, Some(ID_A), &selected).unwrap(),
1153+
resolve_thread_target(
1154+
Uuid::parse_str(channel).unwrap(),
1155+
ID_B,
1156+
Some(ID_A),
1157+
&selected,
1158+
)
1159+
.unwrap(),
11161160
ID_A
11171161
);
11181162
}

0 commit comments

Comments
 (0)