Append attachment URL to post content if attachment is too large

This commit is contained in:
silverpill 2023-01-30 02:09:49 +00:00
parent 01c894da9d
commit 5a3ef41277
4 changed files with 31 additions and 13 deletions

View file

@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
- Replace post attachments and other related objects when processing `Update(Note)` activity. - Replace post attachments and other related objects when processing `Update(Note)` activity.
- Append attachment URL to post content if attachment size exceeds limit.
### Changed ### Changed

View file

@ -38,6 +38,9 @@ pub enum FetchError {
#[error(transparent)] #[error(transparent)]
FileError(#[from] std::io::Error), FileError(#[from] std::io::Error),
#[error("file size exceeds limit")]
FileTooLarge,
#[error("too many objects")] #[error("too many objects")]
RecursionError, RecursionError,
@ -122,13 +125,13 @@ pub async fn fetch_file(
let file_size: usize = file_size.try_into() let file_size: usize = file_size.try_into()
.expect("value should be within bounds"); .expect("value should be within bounds");
if file_size > file_max_size { 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_data = response.bytes().await?;
let file_size = file_data.len(); let file_size = file_data.len();
if file_size > file_max_size { 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 let maybe_media_type = maybe_media_type
.map(|media_type| media_type.to_string()) .map(|media_type| media_type.to_string())

View file

@ -6,7 +6,7 @@ use uuid::Uuid;
use crate::activitypub::{ use crate::activitypub::{
constants::{AP_MEDIA_TYPE, AP_PUBLIC, AS_MEDIA_TYPE}, constants::{AP_MEDIA_TYPE, AP_PUBLIC, AS_MEDIA_TYPE},
fetcher::fetchers::fetch_file, fetcher::fetchers::{fetch_file, FetchError},
fetcher::helpers::{ fetcher::helpers::{
get_or_import_profile_by_actor_address, get_or_import_profile_by_actor_address,
get_or_import_profile_by_actor_id, get_or_import_profile_by_actor_id,
@ -129,10 +129,11 @@ pub async fn get_object_attachments(
db_client: &impl DatabaseClient, db_client: &impl DatabaseClient,
object: &Object, object: &Object,
author: &DbActorProfile, author: &DbActorProfile,
) -> Result<Vec<Uuid>, HandlerError> { ) -> Result<(Vec<Uuid>, Vec<String>), HandlerError> {
let instance = config.instance(); let instance = config.instance();
let media_dir = config.media_dir(); let media_dir = config.media_dir();
let mut attachments = vec![]; let mut attachments = vec![];
let mut unprocessed = vec![];
if let Some(ref value) = object.attachment { if let Some(ref value) = object.attachment {
let list: Vec<Attachment> = parse_property_value(value) let list: Vec<Attachment> = parse_property_value(value)
.map_err(|_| ValidationError("invalid attachment property"))?; .map_err(|_| ValidationError("invalid attachment property"))?;
@ -157,17 +158,24 @@ pub async fn get_object_attachments(
}; };
let attachment_url = attachment.url let attachment_url = attachment.url
.ok_or(ValidationError("attachment URL is missing"))?; .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, &instance,
&attachment_url, &attachment_url,
attachment.media_type.as_deref(), attachment.media_type.as_deref(),
ATTACHMENT_MAX_SIZE, ATTACHMENT_MAX_SIZE,
&media_dir, &media_dir,
).await ).await {
.map_err(|err| { Ok(file) => file,
log::warn!("{}", err); Err(FetchError::FileTooLarge) => {
ValidationError("failed to fetch attachment") 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); log::info!("downloaded attachment {}", attachment_url);
downloaded.push((file_name, file_size, maybe_media_type)); downloaded.push((file_name, file_size, maybe_media_type));
// Stop downloading if limit is reached // Stop downloading if limit is reached
@ -187,7 +195,7 @@ pub async fn get_object_attachments(
attachments.push(db_attachment.id); attachments.push(db_attachment.id);
}; };
}; };
Ok(attachments) Ok((attachments, unprocessed))
} }
pub async fn get_object_tags( pub async fn get_object_tags(
@ -498,12 +506,15 @@ pub async fn handle_note(
let object_url = get_object_url(&object)?; let object_url = get_object_url(&object)?;
content += &create_content_link(object_url); content += &create_content_link(object_url);
}; };
let attachments = get_object_attachments( let (attachments, unprocessed) = get_object_attachments(
config, config,
db_client, db_client,
&object, &object,
&author, &author,
).await?; ).await?;
for attachment_url in unprocessed {
content += &create_content_link(attachment_url);
};
if content.is_empty() && attachments.is_empty() { if content.is_empty() && attachments.is_empty() {
return Err(ValidationError("post is empty").into()); return Err(ValidationError("post is empty").into());
}; };

View file

@ -54,12 +54,15 @@ async fn handle_update_note(
let object_url = get_object_url(&object)?; let object_url = get_object_url(&object)?;
content += &create_content_link(object_url); content += &create_content_link(object_url);
}; };
let attachments = get_object_attachments( let (attachments, unprocessed) = get_object_attachments(
config, config,
db_client, db_client,
&object, &object,
&post.author, &post.author,
).await?; ).await?;
for attachment_url in unprocessed {
content += &create_content_link(attachment_url);
};
if content.is_empty() && attachments.is_empty() { if content.is_empty() && attachments.is_empty() {
return Err(ValidationError("post is empty").into()); return Err(ValidationError("post is empty").into());
}; };