mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(cli): allow generic file uploads
Co-authored-by: npub1x4hk035p3p9q39a3fcrd2fe30lpkrhr5dwe0cqzzjphxyyh8m0gsq4vqap <356f67c681884a0897b14e06d527317fc361dc746bb2fc0042906e6212e7dbd1@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1x4hk035p3p9q39a3fcrd2fe30lpkrhr5dwe0cqzzjphxyyh8m0gsq4vqap <356f67c681884a0897b14e06d527317fc361dc746bb2fc0042906e6212e7dbd1@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1x4hk035p3p9q39a3fcrd2fe30lpkrhr5dwe0cqzzjphxyyh8m0gsq4vqap <356f67c681884a0897b14e06d527317fc361dc746bb2fc0042906e6212e7dbd1@buzz.block.builderlab.xyz>
This commit is contained in:
parent
cca8839034
commit
e2819b9ac4
@@ -75,6 +75,29 @@ const MAX_IMAGE_BYTES: u64 = 50 * 1024 * 1024;
|
||||
/// Maximum file size for video uploads (500 MB).
|
||||
const MAX_VIDEO_BYTES: u64 = 500 * 1024 * 1024;
|
||||
|
||||
/// Maximum file size for generic attachment uploads (100 MB).
|
||||
const MAX_FILE_BYTES: u64 = 100 * 1024 * 1024;
|
||||
|
||||
/// Return the client-side size cap for an upload MIME type.
|
||||
///
|
||||
/// Known media must use an explicitly supported image/video format. Other
|
||||
/// content is a generic attachment and is validated again by the relay.
|
||||
fn upload_size_limit(mime: &str) -> Result<u64, CliError> {
|
||||
let is_media =
|
||||
mime.starts_with("image/") || mime.starts_with("video/") || mime.starts_with("audio/");
|
||||
if is_media && !ALLOWED_MIMES.contains(&mime) {
|
||||
return Err(CliError::Usage(format!("unsupported file type: {mime}")));
|
||||
}
|
||||
|
||||
if mime.starts_with("video/") {
|
||||
Ok(MAX_VIDEO_BYTES)
|
||||
} else if mime.starts_with("image/") {
|
||||
Ok(MAX_IMAGE_BYTES)
|
||||
} else {
|
||||
Ok(MAX_FILE_BYTES)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sign a NIP-98 HTTP auth event (kind:27235) and return the Authorization header value.
|
||||
///
|
||||
/// The event includes:
|
||||
@@ -1113,16 +1136,9 @@ impl BuzzClient {
|
||||
.map(|t| t.mime_type().to_string())
|
||||
.unwrap_or_else(|| "application/octet-stream".to_string());
|
||||
|
||||
if !ALLOWED_MIMES.contains(&mime.as_str()) {
|
||||
return Err(CliError::Usage(format!("unsupported file type: {mime}")));
|
||||
}
|
||||
|
||||
// 3. Size check
|
||||
let max = if mime.starts_with("video/") {
|
||||
MAX_VIDEO_BYTES
|
||||
} else {
|
||||
MAX_IMAGE_BYTES
|
||||
};
|
||||
// 3. Enforce media allowlist and the matching client-side size cap.
|
||||
// Generic attachments are deny-listed and re-sniffed by the relay.
|
||||
let max = upload_size_limit(&mime)?;
|
||||
if bytes.len() as u64 > max {
|
||||
return Err(CliError::Usage(format!(
|
||||
"file too large: {} bytes (max {})",
|
||||
@@ -2297,10 +2313,32 @@ mod retry_policy_tests {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
advance_query_cursor, create_response_with_id, extract_relay_response_field, BuzzClient,
|
||||
advance_query_cursor, create_response_with_id, extract_relay_response_field,
|
||||
upload_size_limit, BuzzClient, MAX_FILE_BYTES, MAX_IMAGE_BYTES, MAX_VIDEO_BYTES,
|
||||
};
|
||||
use nostr::{EventBuilder, Keys, Kind, Tag};
|
||||
|
||||
#[test]
|
||||
fn upload_size_limit_accepts_plain_text_as_generic_attachment() {
|
||||
let mime = infer::get(b"# Markdown attachment\n")
|
||||
.map(|kind| kind.mime_type())
|
||||
.unwrap_or("application/octet-stream");
|
||||
assert_eq!(mime, "application/octet-stream");
|
||||
assert_eq!(upload_size_limit(mime).unwrap(), MAX_FILE_BYTES);
|
||||
assert_eq!(
|
||||
upload_size_limit("application/pdf").unwrap(),
|
||||
MAX_FILE_BYTES
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upload_size_limit_preserves_media_allowlist_and_caps() {
|
||||
assert_eq!(upload_size_limit("image/png").unwrap(), MAX_IMAGE_BYTES);
|
||||
assert_eq!(upload_size_limit("video/mp4").unwrap(), MAX_VIDEO_BYTES);
|
||||
assert!(upload_size_limit("image/svg+xml").is_err());
|
||||
assert!(upload_size_limit("audio/mpeg").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn query_cursor_uses_last_events_composite_sort_key() {
|
||||
let mut filter = serde_json::json!({"kinds": [39000], "limit": 500});
|
||||
|
||||
Reference in New Issue
Block a user