diff --git a/CHANGELOG.md b/CHANGELOG.md index b7bedcb..46bb05e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Accept webfinger requests where `resource` is actor ID. - Adeed support for `as:Public` audience identifier. +### Changed + +- Save downloaded media as "unknown" if its media type is not supported. + ### Removed - `/api/v1/accounts/move_followers` API endpoint. diff --git a/src/activitypub/fetcher/fetchers.rs b/src/activitypub/fetcher/fetchers.rs index a11fef4..38e97fc 100644 --- a/src/activitypub/fetcher/fetchers.rs +++ b/src/activitypub/fetcher/fetchers.rs @@ -12,7 +12,11 @@ use crate::http_signatures::create::{ create_http_signature, HttpSignatureError, }; -use crate::utils::files::{save_file, sniff_media_type}; +use crate::utils::files::{ + save_file, + sniff_media_type, + SUPPORTED_MEDIA_TYPES, +}; use crate::utils::urls::guess_protocol; use crate::webfinger::types::{ActorAddress, JsonResourceDescriptor}; @@ -118,7 +122,20 @@ pub async fn fetch_file( if file_data.len() > FILE_MAX_SIZE as usize { return Err(FetchError::OtherError("file is too large")); }; - let maybe_media_type = sniff_media_type(&file_data); + let maybe_media_type = sniff_media_type(&file_data) + // Remove media type if it is not supported to prevent XSS + .filter(|media_type| { + if SUPPORTED_MEDIA_TYPES.contains(&media_type.as_str()) { + true + } else { + log::info!( + "unsupported media type {}: {}", + media_type, + url, + ); + false + } + }); let file_name = save_file( file_data.to_vec(), output_dir, diff --git a/src/activitypub/handlers/create.rs b/src/activitypub/handlers/create.rs index 17004b5..73a7d02 100644 --- a/src/activitypub/handlers/create.rs +++ b/src/activitypub/handlers/create.rs @@ -175,7 +175,7 @@ pub async fn handle_note( }; let attachment_url = attachment.url .ok_or(ValidationError("attachment URL is missing"))?; - let (file_name, media_type) = fetch_file( + let (file_name, maybe_media_type) = fetch_file( instance, &attachment_url, media_dir, @@ -185,22 +185,19 @@ pub async fn handle_note( ValidationError("failed to fetch attachment") })?; log::info!("downloaded attachment {}", attachment_url); - downloaded.push(( - file_name, - attachment.media_type.or(media_type), - )); + downloaded.push((file_name, maybe_media_type)); // Stop downloading if limit is reached if downloaded.len() >= ATTACHMENTS_MAX_NUM { log::warn!("too many attachments"); break; }; }; - for (file_name, media_type) in downloaded { + for (file_name, maybe_media_type) in downloaded { let db_attachment = create_attachment( db_client, &author.id, file_name, - media_type, + maybe_media_type, ).await?; attachments.push(db_attachment.id); };