diff --git a/src/apub.rs b/src/apub.rs index 195a6a8..f34eb69 100644 --- a/src/apub.rs +++ b/src/apub.rs @@ -35,7 +35,7 @@ pub struct AnyExistingObject { ext: HashMap, } -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "PascalCase")] pub enum ValidTypes { Announce, diff --git a/src/error.rs b/src/error.rs index 3814608..6436b3d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -35,6 +35,9 @@ pub enum MyError { #[error("Couldn't decode base64")] Base64(#[from] base64::DecodeError), + #[error("Actor ({0}), or Actor's server, is not subscribed")] + NotSubscribed(String), + #[error("Actor is blocked, {0}")] Blocked(String), @@ -77,13 +80,23 @@ pub enum MyError { impl ResponseError for MyError { fn status_code(&self) -> StatusCode { - StatusCode::INTERNAL_SERVER_ERROR + match self { + MyError::Blocked(_) + | MyError::Whitelist(_) + | MyError::WrongActor(_) + | MyError::BadActor(_, _) => StatusCode::FORBIDDEN, + MyError::Duplicate => StatusCode::ACCEPTED, + MyError::Kind(_) => StatusCode::BAD_REQUEST, + _ => StatusCode::INTERNAL_SERVER_ERROR, + } } fn error_response(&self) -> HttpResponse { - HttpResponse::InternalServerError() + HttpResponse::build(self.status_code()) .header("Content-Type", "application/activity+json") - .json(serde_json::json!({})) + .json(serde_json::json!({ + "error": self.to_string(), + })) } } diff --git a/src/inbox.rs b/src/inbox.rs index 98cbfae..60ee48e 100644 --- a/src/inbox.rs +++ b/src/inbox.rs @@ -14,6 +14,13 @@ use activitystreams::{ use actix_web::{web, HttpResponse}; use futures::join; use http_signature_normalization_actix::middleware::SignatureVerified; +use log::error; + +fn public() -> XsdAnyUri { + "https://www.w3.org/ns/activitystreams#Public" + .parse() + .unwrap() +} pub async fn inbox( db: web::Data, @@ -26,8 +33,11 @@ pub async fn inbox( let actor = client.fetch_actor(&input.actor).await?; - let (is_blocked, is_whitelisted) = - join!(state.is_blocked(&actor.id), state.is_whitelisted(&actor.id),); + let (is_blocked, is_whitelisted, is_listener) = join!( + state.is_blocked(&actor.id), + state.is_whitelisted(&actor.id), + state.is_listener(&actor.id) + ); if is_blocked { return Err(MyError::Blocked(actor.id.to_string())); @@ -37,8 +47,12 @@ pub async fn inbox( return Err(MyError::Whitelist(actor.id.to_string())); } + if input.kind != ValidTypes::Follow && !is_listener { + return Err(MyError::NotSubscribed(actor.id.to_string())); + } + if actor.public_key.id.as_str() != verified.key_id() { - log::error!("Bad actor, more info: {:?}", input); + error!("Bad actor, more info: {:?}", input); return Err(MyError::BadActor( actor.public_key.id.to_string(), verified.key_id().to_owned(), @@ -72,8 +86,7 @@ async fn handle_undo( let my_id: XsdAnyUri = state.generate_url(UrlKind::Actor).parse()?; - if !input.object.child_object_is(&my_id) { - log::error!("Wrong actor, more info: {:?}", input); + if !input.object.child_object_is(&my_id) && !input.object.child_object_is(&public()) { return Err(MyError::WrongActor(input.object.id().to_string())); }