diff --git a/CHANGELOG.md b/CHANGELOG.md index fb7be85..f1f7b44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Replace post attachments and other related objects when processing `Update(Note)` activity. +- Append attachment URL to post content if attachment size exceeds limit. ### Changed diff --git a/src/activitypub/fetcher/fetchers.rs b/src/activitypub/fetcher/fetchers.rs index 000beab..e828a59 100644 --- a/src/activitypub/fetcher/fetchers.rs +++ b/src/activitypub/fetcher/fetchers.rs @@ -38,6 +38,9 @@ pub enum FetchError { #[error(transparent)] FileError(#[from] std::io::Error), + #[error("file size exceeds limit")] + FileTooLarge, + #[error("too many objects")] RecursionError, @@ -122,13 +125,13 @@ pub async fn fetch_file( let file_size: usize = file_size.try_into() .expect("value should be within bounds"); if file_size > file_max_size { - return Err(FetchError::OtherError("file is too large")); + return Err(FetchError::FileTooLarge); }; }; let file_data = response.bytes().await?; let file_size = file_data.len(); if file_size > file_max_size { - return Err(FetchError::OtherError("file is too large")); + return Err(FetchError::FileTooLarge); }; let maybe_media_type = maybe_media_type .map(|media_type| media_type.to_string()) diff --git a/src/activitypub/handlers/create.rs b/src/activitypub/handlers/create.rs index 13f3a01..7115516 100644 --- a/src/activitypub/handlers/create.rs +++ b/src/activitypub/handlers/create.rs @@ -6,7 +6,7 @@ use uuid::Uuid; use crate::activitypub::{ constants::{AP_MEDIA_TYPE, AP_PUBLIC, AS_MEDIA_TYPE}, - fetcher::fetchers::fetch_file, + fetcher::fetchers::{fetch_file, FetchError}, fetcher::helpers::{ get_or_import_profile_by_actor_address, get_or_import_profile_by_actor_id, @@ -129,10 +129,11 @@ pub async fn get_object_attachments( db_client: &impl DatabaseClient, object: &Object, author: &DbActorProfile, -) -> Result, HandlerError> { +) -> Result<(Vec, Vec), HandlerError> { let instance = config.instance(); let media_dir = config.media_dir(); let mut attachments = vec![]; + let mut unprocessed = vec![]; if let Some(ref value) = object.attachment { let list: Vec = parse_property_value(value) .map_err(|_| ValidationError("invalid attachment property"))?; @@ -157,17 +158,24 @@ pub async fn get_object_attachments( }; let attachment_url = attachment.url .ok_or(ValidationError("attachment URL is missing"))?; - let (file_name, file_size, maybe_media_type) = fetch_file( + let (file_name, file_size, maybe_media_type) = match fetch_file( &instance, &attachment_url, attachment.media_type.as_deref(), ATTACHMENT_MAX_SIZE, &media_dir, - ).await - .map_err(|err| { - log::warn!("{}", err); - ValidationError("failed to fetch attachment") - })?; + ).await { + Ok(file) => file, + Err(FetchError::FileTooLarge) => { + log::warn!("attachment is too large: {}", attachment_url); + unprocessed.push(attachment_url); + continue; + }, + Err(other_error) => { + log::warn!("{}", other_error); + return Err(ValidationError("failed to fetch attachment").into()); + }, + }; log::info!("downloaded attachment {}", attachment_url); downloaded.push((file_name, file_size, maybe_media_type)); // Stop downloading if limit is reached @@ -187,7 +195,7 @@ pub async fn get_object_attachments( attachments.push(db_attachment.id); }; }; - Ok(attachments) + Ok((attachments, unprocessed)) } pub async fn get_object_tags( @@ -498,12 +506,15 @@ pub async fn handle_note( let object_url = get_object_url(&object)?; content += &create_content_link(object_url); }; - let attachments = get_object_attachments( + let (attachments, unprocessed) = get_object_attachments( config, db_client, &object, &author, ).await?; + for attachment_url in unprocessed { + content += &create_content_link(attachment_url); + }; if content.is_empty() && attachments.is_empty() { return Err(ValidationError("post is empty").into()); }; diff --git a/src/activitypub/handlers/update.rs b/src/activitypub/handlers/update.rs index 9a7d72f..1d8eb9c 100644 --- a/src/activitypub/handlers/update.rs +++ b/src/activitypub/handlers/update.rs @@ -54,12 +54,15 @@ async fn handle_update_note( let object_url = get_object_url(&object)?; content += &create_content_link(object_url); }; - let attachments = get_object_attachments( + let (attachments, unprocessed) = get_object_attachments( config, db_client, &object, &post.author, ).await?; + for attachment_url in unprocessed { + content += &create_content_link(attachment_url); + }; if content.is_empty() && attachments.is_empty() { return Err(ValidationError("post is empty").into()); };