Ignore NotFound errors when receiving activities (fixes #2240)

This commit is contained in:
Felix Ableitner 2024-09-25 13:21:20 +02:00
parent f6a24e133a
commit 99cdf742d4
4 changed files with 34 additions and 12 deletions

1
Cargo.lock generated
View file

@ -2795,6 +2795,7 @@ dependencies = [
name = "lemmy_utils" name = "lemmy_utils"
version = "0.19.6-beta.7" version = "0.19.6-beta.7"
dependencies = [ dependencies = [
"activitypub_federation",
"actix-web", "actix-web",
"anyhow", "anyhow",
"cfg-if", "cfg-if",

View file

@ -17,7 +17,7 @@ use lemmy_db_schema::{
source::{activity::SentActivity, community::Community}, source::{activity::SentActivity, community::Community},
CommunityVisibility, CommunityVisibility,
}; };
use lemmy_utils::error::{LemmyErrorType, LemmyResult}; use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ops::Deref, time::Duration}; use std::{ops::Deref, time::Duration};
use tokio::time::timeout; use tokio::time::timeout;
@ -43,9 +43,16 @@ pub async fn shared_inbox(
// avoid taking a long time to process an incoming activity when a required data fetch times out. // avoid taking a long time to process an incoming activity when a required data fetch times out.
// In this case our own instance would timeout and be marked as dead by the sender. Better to // In this case our own instance would timeout and be marked as dead by the sender. Better to
// consider the activity broken and move on. // consider the activity broken and move on.
timeout(INCOMING_ACTIVITY_TIMEOUT, receive_fut) let res = timeout(INCOMING_ACTIVITY_TIMEOUT, receive_fut).await;
.await
.map_err(|_| LemmyErrorType::InboxTimeout)? match res {
// Ignore NotFound error, usually means that the sending actor was deleted and sent a delete
// activity: https://github.com/LemmyNet/lemmy/issues/2240
Ok(Err(LemmyError {error_type: LemmyErrorType::NotFound, ..})) => Ok(HttpResponse::Ok().finish()),
// Top-level error means we hit the send timeout
Err(_) => Err(LemmyErrorType::InboxTimeout.into()),
Ok(other) => other,
}
} }
/// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub /// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub

View file

@ -47,6 +47,7 @@ full = [
"dep:uuid", "dep:uuid",
"dep:itertools", "dep:itertools",
"dep:markdown-it", "dep:markdown-it",
"dep:activitypub_federation"
] ]
[dependencies] [dependencies]
@ -80,6 +81,7 @@ lettre = { version = "0.11.8", default-features = false, features = [
markdown-it = { version = "0.6.1", optional = true } markdown-it = { version = "0.6.1", optional = true }
ts-rs = { workspace = true, optional = true } ts-rs = { workspace = true, optional = true }
enum-map = { workspace = true, optional = true } enum-map = { workspace = true, optional = true }
activitypub_federation = { workspace = true, optional = true }
cfg-if = "1" cfg-if = "1"
clearurls = { version = "0.0.4", features = ["linkify"] } clearurls = { version = "0.0.4", features = ["linkify"] }

View file

@ -198,10 +198,14 @@ cfg_if! {
{ {
fn from(t: T) -> Self { fn from(t: T) -> Self {
let cause = t.into(); let cause = t.into();
let error_type = match cause.downcast_ref::<diesel::result::Error>() { let error_type = if let Some(&diesel::NotFound) = cause.downcast_ref::<diesel::result::Error>() {
Some(&diesel::NotFound) => LemmyErrorType::NotFound, LemmyErrorType::NotFound
_ => LemmyErrorType::Unknown(format!("{}", &cause)) } else if let Some(activitypub_federation::error::Error::NotFound) = cause.downcast_ref::<activitypub_federation::error::Error>() {
}; LemmyErrorType::NotFound
}
else {
LemmyErrorType::Unknown(format!("{}", &cause))
};
LemmyError { LemmyError {
error_type, error_type,
inner: cause, inner: cause,
@ -231,11 +235,15 @@ cfg_if! {
impl actix_web::error::ResponseError for LemmyError { impl actix_web::error::ResponseError for LemmyError {
fn status_code(&self) -> actix_web::http::StatusCode { fn status_code(&self) -> actix_web::http::StatusCode {
if self.error_type == LemmyErrorType::IncorrectLogin { if self.error_type == LemmyErrorType::IncorrectLogin {
return actix_web::http::StatusCode::UNAUTHORIZED; actix_web::http::StatusCode::UNAUTHORIZED
} }
match self.inner.downcast_ref::<diesel::result::Error>() { else if let Some(&diesel::NotFound) = self.inner.downcast_ref::<diesel::result::Error>() {
Some(diesel::result::Error::NotFound) => actix_web::http::StatusCode::NOT_FOUND, actix_web::http::StatusCode::NOT_FOUND
_ => actix_web::http::StatusCode::BAD_REQUEST, } else if let Some(activitypub_federation::error::Error::NotFound) = self.inner.downcast_ref::<activitypub_federation::error::Error>() {
actix_web::http::StatusCode::NOT_FOUND
}
else {
actix_web::http::StatusCode::BAD_REQUEST
} }
} }
@ -320,6 +328,10 @@ cfg_if! {
assert_eq!(LemmyErrorType::NotFound, not_found_error.error_type); assert_eq!(LemmyErrorType::NotFound, not_found_error.error_type);
assert_eq!(404, not_found_error.status_code()); assert_eq!(404, not_found_error.status_code());
let apub_not_found_error = LemmyError::from(activitypub_federation::error::Error::NotFound);
assert_eq!(LemmyErrorType::NotFound, apub_not_found_error.error_type);
assert_eq!(404, apub_not_found_error.status_code());
let other_error = LemmyError::from(diesel::result::Error::NotInTransaction); let other_error = LemmyError::from(diesel::result::Error::NotInTransaction);
assert!(matches!(other_error.error_type, LemmyErrorType::Unknown{..})); assert!(matches!(other_error.error_type, LemmyErrorType::Unknown{..}));
assert_eq!(400, other_error.status_code()); assert_eq!(400, other_error.status_code());