diff --git a/crates/buzz-acp/src/relay_skills.rs b/crates/buzz-acp/src/relay_skills.rs index 93536c0b79..0df4370b42 100644 --- a/crates/buzz-acp/src/relay_skills.rs +++ b/crates/buzz-acp/src/relay_skills.rs @@ -8,6 +8,7 @@ use crate::relay::RestClient; const SKILL_KIND: u16 = 30023; const MAX_SKILLS: usize = 64; +const MAX_SLUG_BYTES: usize = 80; const MAX_DESCRIPTION_BYTES: usize = 1024; #[derive(Debug, Clone, PartialEq, Eq)] @@ -24,7 +25,14 @@ fn parse_coordinate(raw: &str) -> Option { } let publisher = PublicKey::from_hex(parts.next()?).ok()?; let slug = parts.next()?.to_string(); - (!slug.is_empty()).then_some(Coordinate { + (!slug.is_empty() + && slug.len() <= MAX_SLUG_BYTES + && slug.chars().all(|character| { + character.is_ascii_lowercase() + || character.is_ascii_digit() + || matches!(character, '-' | '_' | '.') + })) + .then_some(Coordinate { raw: raw.to_string(), publisher, slug, @@ -154,6 +162,18 @@ mod tests { use super::*; use nostr::{EventBuilder, Keys, Tag, Timestamp}; + #[test] + fn rejects_slugs_the_lazy_fetch_command_cannot_accept() { + let publisher = Keys::generate().public_key().to_hex(); + assert!(parse_coordinate(&format!("30023:{publisher}:valid_slug-1.0")).is_some()); + assert!(parse_coordinate(&format!("30023:{publisher}:Uppercase")).is_none()); + assert!(parse_coordinate(&format!( + "30023:{publisher}:{}", + "x".repeat(MAX_SLUG_BYTES + 1) + )) + .is_none()); + } + #[test] fn exact_query_filters_do_not_admit_author_slug_cross_products() { let alpha = Keys::generate(); diff --git a/desktop/src-tauri/src/managed_agents/relay_skills.rs b/desktop/src-tauri/src/managed_agents/relay_skills.rs index 1bf20f3399..15ae5af873 100644 --- a/desktop/src-tauri/src/managed_agents/relay_skills.rs +++ b/desktop/src-tauri/src/managed_agents/relay_skills.rs @@ -17,7 +17,7 @@ use tauri::State; use crate::{app_state::AppState, native_relay_client::NativeRelayClient}; pub const RELAY_SKILL_KIND: u16 = 30023; -pub const MAX_RELAY_SKILL_SLUG_BYTES: usize = 255; +pub const MAX_RELAY_SKILL_SLUG_BYTES: usize = 80; pub const MAX_AGENT_SKILL_NAME_BYTES: usize = 64; pub const MAX_AGENT_SKILL_DESCRIPTION_BYTES: usize = 1024; pub const MAX_ASSIGNED_RELAY_SKILLS: usize = 64;