relay/src/routes/inbox.rs

233 lines
6.8 KiB
Rust
Raw Normal View History

2020-03-16 04:15:50 +00:00
use crate::{
2020-05-21 21:24:56 +00:00
apub::{AcceptedActivities, AcceptedUndoObjects, UndoTypes, ValidTypes},
config::{Config, UrlKind},
2021-02-10 04:05:06 +00:00
data::{ActorCache, State},
db::Actor,
2021-09-18 17:55:39 +00:00
error::{Error, ErrorKind},
2020-03-30 17:10:04 +00:00
jobs::apub::{Announce, Follow, Forward, Reject, Undo},
jobs::JobServer,
2020-03-18 04:35:20 +00:00
requests::Requests,
2020-03-23 17:38:39 +00:00
routes::accepted,
2020-03-16 04:15:50 +00:00
};
2020-09-07 21:51:02 +00:00
use activitystreams::{
2022-01-17 22:54:45 +00:00
activity, base::AnyBase, iri_string::types::IriString, prelude::*, primitives::OneOrMany,
public,
2020-05-21 21:24:56 +00:00
};
2020-03-18 04:35:20 +00:00
use actix_web::{web, HttpResponse};
use http_signature_normalization_actix::prelude::{DigestVerified, SignatureVerified};
2021-09-18 17:55:39 +00:00
use tracing::error;
2020-03-18 04:58:13 +00:00
2022-11-01 21:50:23 +00:00
#[tracing::instrument(name = "Inbox", skip(actors, client, jobs, config, state))]
2021-02-10 04:17:20 +00:00
pub(crate) async fn route(
2020-03-15 02:05:40 +00:00
state: web::Data<State>,
2020-03-23 22:17:53 +00:00
actors: web::Data<ActorCache>,
config: web::Data<Config>,
2020-03-18 04:35:20 +00:00
client: web::Data<Requests>,
jobs: web::Data<JobServer>,
2020-05-21 21:24:56 +00:00
input: web::Json<AcceptedActivities>,
2020-04-26 01:49:29 +00:00
verified: Option<(SignatureVerified, DigestVerified)>,
2021-09-18 17:55:39 +00:00
) -> Result<HttpResponse, Error> {
2020-03-15 02:05:40 +00:00
let input = input.into_inner();
2020-05-21 21:24:56 +00:00
let actor = actors
.get(
2021-09-18 17:55:39 +00:00
input.actor()?.as_single_id().ok_or(ErrorKind::MissingId)?,
2020-05-21 21:24:56 +00:00
&client,
)
.await?
.into_inner();
2021-02-10 04:05:06 +00:00
let is_allowed = state.db.is_allowed(actor.id.clone()).await?;
let is_connected = state.db.is_connected(actor.id.clone()).await?;
2021-02-10 04:05:06 +00:00
if !is_allowed {
2021-09-18 17:55:39 +00:00
return Err(ErrorKind::NotAllowed(actor.id.to_string()).into());
}
2021-02-10 04:05:06 +00:00
if !is_connected && !valid_without_listener(&input)? {
2021-09-18 17:55:39 +00:00
return Err(ErrorKind::NotSubscribed(actor.id.to_string()).into());
2020-03-18 04:58:13 +00:00
}
2020-04-26 01:49:29 +00:00
if config.validate_signatures() && verified.is_none() {
2021-09-18 17:55:39 +00:00
return Err(ErrorKind::NoSignature(actor.public_key_id.to_string()).into());
} else if config.validate_signatures() {
2020-04-26 01:49:29 +00:00
if let Some((verified, _)) = verified {
2020-03-23 22:17:53 +00:00
if actor.public_key_id.as_str() != verified.key_id() {
error!("Bad actor, more info: {:?}", input);
2021-09-18 17:55:39 +00:00
return Err(ErrorKind::BadActor(
2020-03-23 22:17:53 +00:00
actor.public_key_id.to_string(),
verified.key_id().to_owned(),
2021-09-18 17:55:39 +00:00
)
.into());
}
}
2020-03-17 19:52:33 +00:00
}
2021-09-18 17:55:39 +00:00
match input.kind().ok_or(ErrorKind::MissingKind)? {
2020-03-30 17:10:04 +00:00
ValidTypes::Accept => handle_accept(&config, input).await?,
ValidTypes::Reject => handle_reject(&config, &jobs, input, actor).await?,
2020-03-15 22:37:53 +00:00
ValidTypes::Announce | ValidTypes::Create => {
2020-03-30 17:10:04 +00:00
handle_announce(&state, &jobs, input, actor).await?
}
2021-02-10 06:44:48 +00:00
ValidTypes::Follow => handle_follow(&config, &jobs, input, actor).await?,
2020-03-30 17:10:04 +00:00
ValidTypes::Delete | ValidTypes::Update => handle_forward(&jobs, input, actor).await?,
2021-02-10 04:05:06 +00:00
ValidTypes::Undo => handle_undo(&config, &jobs, input, actor, is_connected).await?,
2020-03-30 17:10:04 +00:00
};
Ok(accepted(serde_json::json!({})))
}
2021-09-18 17:55:39 +00:00
fn valid_without_listener(input: &AcceptedActivities) -> Result<bool, Error> {
2020-05-21 21:24:56 +00:00
match input.kind() {
Some(ValidTypes::Follow) => Ok(true),
2022-01-17 22:54:45 +00:00
Some(ValidTypes::Undo) => Ok(single_object(input.object_unchecked())?.is_kind("Follow")),
2020-05-21 21:24:56 +00:00
_ => Ok(false),
2020-03-15 02:05:40 +00:00
}
2020-03-15 22:37:53 +00:00
}
2020-03-15 02:05:40 +00:00
2021-09-18 17:55:39 +00:00
fn kind_str(base: &AnyBase) -> Result<&str, Error> {
base.kind_str()
.ok_or(ErrorKind::MissingKind)
.map_err(Into::into)
2020-05-21 21:24:56 +00:00
}
2022-01-17 22:54:45 +00:00
fn id_string(id: Option<&IriString>) -> Result<String, Error> {
2021-09-18 17:55:39 +00:00
id.map(|s| s.to_string())
.ok_or(ErrorKind::MissingId)
.map_err(Into::into)
2020-05-21 21:24:56 +00:00
}
2021-09-18 17:55:39 +00:00
fn single_object(o: &OneOrMany<AnyBase>) -> Result<&AnyBase, Error> {
o.as_one().ok_or(ErrorKind::ObjectCount).map_err(Into::into)
2020-05-21 21:24:56 +00:00
}
2021-09-18 17:55:39 +00:00
async fn handle_accept(config: &Config, input: AcceptedActivities) -> Result<(), Error> {
2022-01-17 22:54:45 +00:00
let base = single_object(input.object_unchecked())?.clone();
let follow = if let Some(follow) = activity::Follow::from_any_base(base)? {
2020-05-21 21:24:56 +00:00
follow
} else {
2022-01-17 22:54:45 +00:00
return Err(ErrorKind::Kind(
kind_str(single_object(input.object_unchecked())?)?.to_owned(),
)
.into());
2020-05-21 21:24:56 +00:00
};
if !follow.actor_is(&config.generate_url(UrlKind::Actor)) {
2021-09-18 17:55:39 +00:00
return Err(ErrorKind::WrongActor(id_string(follow.actor()?.as_single_id())?).into());
}
2020-03-30 17:10:04 +00:00
Ok(())
}
async fn handle_reject(
config: &Config,
jobs: &JobServer,
2020-05-21 21:24:56 +00:00
input: AcceptedActivities,
2020-03-23 22:17:53 +00:00
actor: Actor,
2021-09-18 17:55:39 +00:00
) -> Result<(), Error> {
2022-01-17 22:54:45 +00:00
let base = single_object(input.object_unchecked())?.clone();
let follow = if let Some(follow) = activity::Follow::from_any_base(base)? {
2020-05-21 21:24:56 +00:00
follow
} else {
2022-01-17 22:54:45 +00:00
return Err(ErrorKind::Kind(
kind_str(single_object(input.object_unchecked())?)?.to_owned(),
)
.into());
2020-05-21 21:24:56 +00:00
};
if !follow.actor_is(&config.generate_url(UrlKind::Actor)) {
2021-09-18 17:55:39 +00:00
return Err(ErrorKind::WrongActor(id_string(follow.actor()?.as_single_id())?).into());
}
2021-10-11 19:19:32 +00:00
jobs.queue(Reject(actor)).await?;
2020-03-30 17:10:04 +00:00
Ok(())
}
2020-03-15 22:37:53 +00:00
async fn handle_undo(
config: &Config,
jobs: &JobServer,
2020-05-21 21:24:56 +00:00
input: AcceptedActivities,
2020-03-23 22:17:53 +00:00
actor: Actor,
is_listener: bool,
2021-09-18 17:55:39 +00:00
) -> Result<(), Error> {
2022-01-17 22:54:45 +00:00
let any_base = single_object(input.object_unchecked())?.clone();
2020-05-21 21:24:56 +00:00
let undone_object =
2021-09-18 17:55:39 +00:00
AcceptedUndoObjects::from_any_base(any_base)?.ok_or(ErrorKind::ObjectFormat)?;
2020-03-18 05:43:31 +00:00
2020-05-21 21:24:56 +00:00
if !undone_object.is_kind(&UndoTypes::Follow) {
if is_listener {
2021-10-11 19:19:32 +00:00
jobs.queue(Forward::new(input, actor)).await?;
2020-03-30 17:10:04 +00:00
return Ok(());
} else {
2021-09-18 17:55:39 +00:00
return Err(ErrorKind::NotSubscribed(actor.id.to_string()).into());
}
2020-03-15 22:37:53 +00:00
}
2022-01-17 22:54:45 +00:00
let my_id: IriString = config.generate_url(UrlKind::Actor);
2020-05-21 21:24:56 +00:00
if !undone_object.object_is(&my_id) && !undone_object.object_is(&public()) {
2022-01-17 22:54:45 +00:00
return Err(ErrorKind::WrongActor(id_string(
undone_object.object_unchecked().as_single_id(),
)?)
.into());
}
if !is_listener {
2020-03-30 17:10:04 +00:00
return Ok(());
2020-03-23 22:17:53 +00:00
}
2021-10-11 19:19:32 +00:00
jobs.queue(Undo::new(input, actor)).await?;
2020-03-30 17:10:04 +00:00
Ok(())
2020-03-15 22:37:53 +00:00
}
async fn handle_forward(
jobs: &JobServer,
2020-05-21 21:24:56 +00:00
input: AcceptedActivities,
2020-03-23 22:17:53 +00:00
actor: Actor,
2021-09-18 17:55:39 +00:00
) -> Result<(), Error> {
2021-10-11 19:19:32 +00:00
jobs.queue(Forward::new(input, actor)).await?;
2020-03-15 22:37:53 +00:00
2020-03-30 17:10:04 +00:00
Ok(())
2020-03-15 22:37:53 +00:00
}
2020-03-18 05:43:31 +00:00
async fn handle_announce(
2020-03-18 04:35:20 +00:00
state: &State,
jobs: &JobServer,
2020-05-21 21:24:56 +00:00
input: AcceptedActivities,
2020-03-23 22:17:53 +00:00
actor: Actor,
2021-09-18 17:55:39 +00:00
) -> Result<(), Error> {
2022-01-17 22:54:45 +00:00
let object_id = input
.object_unchecked()
.as_single_id()
.ok_or(ErrorKind::MissingId)?;
2020-03-15 22:37:53 +00:00
if state.is_cached(object_id).await {
2021-09-18 17:55:39 +00:00
return Err(ErrorKind::Duplicate.into());
2020-03-15 22:37:53 +00:00
}
2022-01-17 22:54:45 +00:00
jobs.queue(Announce::new(object_id.to_owned(), actor))
.await?;
2020-03-15 22:37:53 +00:00
2020-03-30 17:10:04 +00:00
Ok(())
2020-03-15 17:49:27 +00:00
}
async fn handle_follow(
config: &Config,
jobs: &JobServer,
2020-05-21 21:24:56 +00:00
input: AcceptedActivities,
2020-03-23 22:17:53 +00:00
actor: Actor,
2021-09-18 17:55:39 +00:00
) -> Result<(), Error> {
2022-01-17 22:54:45 +00:00
let my_id: IriString = config.generate_url(UrlKind::Actor);
2020-03-15 17:49:27 +00:00
2020-05-21 21:24:56 +00:00
if !input.object_is(&my_id) && !input.object_is(&public()) {
2022-01-17 22:54:45 +00:00
return Err(
ErrorKind::WrongActor(id_string(input.object_unchecked().as_single_id())?).into(),
);
2020-03-15 17:49:27 +00:00
}
2021-10-11 19:19:32 +00:00
jobs.queue(Follow::new(input, actor)).await?;
2020-03-15 17:49:27 +00:00
2020-03-30 17:10:04 +00:00
Ok(())
2020-03-15 22:37:53 +00:00
}