Bump version: secrets-mcp-0.5.1 tag already existed while crates had further changes. Made-with: Cursor
150 lines
5.3 KiB
Rust
150 lines
5.3 KiB
Rust
/// Validation constants for input field lengths.
|
|
pub const MAX_NAME_LENGTH: usize = 256;
|
|
pub const MAX_FOLDER_LENGTH: usize = 128;
|
|
pub const MAX_ENTRY_TYPE_LENGTH: usize = 64;
|
|
pub const MAX_NOTES_LENGTH: usize = 10000;
|
|
pub const MAX_TAG_LENGTH: usize = 64;
|
|
pub const MAX_TAG_COUNT: usize = 50;
|
|
pub const MAX_META_KEY_LENGTH: usize = 128;
|
|
pub const MAX_META_VALUE_LENGTH: usize = 4096;
|
|
pub const MAX_META_COUNT: usize = 100;
|
|
|
|
/// Validate input field lengths for MCP tools.
|
|
///
|
|
/// Returns an error if any field exceeds its maximum length.
|
|
pub fn validate_input_lengths(
|
|
name: &str,
|
|
folder: Option<&str>,
|
|
entry_type: Option<&str>,
|
|
notes: Option<&str>,
|
|
) -> Result<(), rmcp::ErrorData> {
|
|
if name.chars().count() > MAX_NAME_LENGTH {
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!("name must be at most {} characters", MAX_NAME_LENGTH),
|
|
None,
|
|
));
|
|
}
|
|
if let Some(folder) = folder
|
|
&& folder.chars().count() > MAX_FOLDER_LENGTH
|
|
{
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!("folder must be at most {} characters", MAX_FOLDER_LENGTH),
|
|
None,
|
|
));
|
|
}
|
|
if let Some(entry_type) = entry_type
|
|
&& entry_type.chars().count() > MAX_ENTRY_TYPE_LENGTH
|
|
{
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!("type must be at most {} characters", MAX_ENTRY_TYPE_LENGTH),
|
|
None,
|
|
));
|
|
}
|
|
if let Some(notes) = notes
|
|
&& notes.chars().count() > MAX_NOTES_LENGTH
|
|
{
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!("notes must be at most {} characters", MAX_NOTES_LENGTH),
|
|
None,
|
|
));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Validate the tags list.
|
|
///
|
|
/// Checks total count and per-tag character length.
|
|
pub fn validate_tags(tags: &[String]) -> Result<(), rmcp::ErrorData> {
|
|
if tags.len() > MAX_TAG_COUNT {
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!("at most {} tags are allowed", MAX_TAG_COUNT),
|
|
None,
|
|
));
|
|
}
|
|
for tag in tags {
|
|
if tag.chars().count() > MAX_TAG_LENGTH {
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!(
|
|
"tag '{}' exceeds the maximum length of {} characters",
|
|
tag, MAX_TAG_LENGTH
|
|
),
|
|
None,
|
|
));
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Validate metadata KV strings (key=value / key:=json format).
|
|
///
|
|
/// Checks total count and per-key/per-value character lengths.
|
|
/// This is a best-effort check on the raw KV strings before parsing;
|
|
/// keys containing `:` path separators are checked as a whole.
|
|
pub fn validate_meta_entries(entries: &[String]) -> Result<(), rmcp::ErrorData> {
|
|
if entries.len() > MAX_META_COUNT {
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!("at most {} metadata entries are allowed", MAX_META_COUNT),
|
|
None,
|
|
));
|
|
}
|
|
for entry in entries {
|
|
// key:=json — check both key and JSON value length
|
|
if let Some((key, value)) = entry.split_once(":=") {
|
|
if key.chars().count() > MAX_META_KEY_LENGTH {
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!(
|
|
"metadata key '{}' exceeds the maximum length of {} characters",
|
|
key, MAX_META_KEY_LENGTH
|
|
),
|
|
None,
|
|
));
|
|
}
|
|
if value.chars().count() > MAX_META_VALUE_LENGTH {
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!(
|
|
"metadata JSON value for key '{}' exceeds the maximum length of {} characters",
|
|
key, MAX_META_VALUE_LENGTH
|
|
),
|
|
None,
|
|
));
|
|
}
|
|
continue;
|
|
}
|
|
// key=value or key@path
|
|
if let Some((key, value)) = entry.split_once('=') {
|
|
if key.chars().count() > MAX_META_KEY_LENGTH {
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!(
|
|
"metadata key '{}' exceeds the maximum length of {} characters",
|
|
key, MAX_META_KEY_LENGTH
|
|
),
|
|
None,
|
|
));
|
|
}
|
|
if value.chars().count() > MAX_META_VALUE_LENGTH {
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!(
|
|
"metadata value for key '{}' exceeds the maximum length of {} characters",
|
|
key, MAX_META_VALUE_LENGTH
|
|
),
|
|
None,
|
|
));
|
|
}
|
|
} else {
|
|
// Fallback: entry without = or := — check total length
|
|
let max_total = MAX_META_KEY_LENGTH + MAX_META_VALUE_LENGTH;
|
|
if entry.chars().count() > max_total {
|
|
let preview = entry.chars().take(50).collect::<String>();
|
|
return Err(rmcp::ErrorData::invalid_params(
|
|
format!(
|
|
"metadata entry '{}' exceeds the maximum length of {} characters",
|
|
preview, max_total
|
|
),
|
|
None,
|
|
));
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|