relay/src/routes/inbox.rs

224 lines
6.4 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,
2020-03-16 04:15:50 +00:00
error::MyError,
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::{
2020-06-20 04:11:02 +00:00
activity, base::AnyBase, prelude::*, primitives::OneOrMany, public, url::Url,
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};
2020-03-18 04:58:13 +00:00
use log::error;
2020-03-23 17:38:39 +00:00
pub 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)>,
2020-03-15 22:37:53 +00:00
) -> Result<HttpResponse, MyError> {
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(
2020-06-20 04:11:02 +00:00
input.actor()?.as_single_id().ok_or(MyError::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 {
return Err(MyError::NotAllowed(actor.id.to_string()));
}
2021-02-10 04:05:06 +00:00
if !is_connected && !valid_without_listener(&input)? {
2020-03-23 22:17:53 +00:00
return Err(MyError::NotSubscribed(actor.inbox.to_string()));
2020-03-18 04:58:13 +00:00
}
2020-04-26 01:49:29 +00:00
if config.validate_signatures() && verified.is_none() {
2020-03-23 22:17:53 +00:00
return Err(MyError::NoSignature(actor.public_key_id.to_string()));
} 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);
return Err(MyError::BadActor(
2020-03-23 22:17:53 +00:00
actor.public_key_id.to_string(),
verified.key_id().to_owned(),
));
}
}
2020-03-17 19:52:33 +00:00
}
2020-05-21 21:24:56 +00:00
match input.kind().ok_or(MyError::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 04:05:06 +00:00
ValidTypes::Follow => handle_follow(&config, &jobs, input, actor, is_connected).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!({})))
}
2020-05-21 21:24:56 +00:00
fn valid_without_listener(input: &AcceptedActivities) -> Result<bool, MyError> {
match input.kind() {
Some(ValidTypes::Follow) => Ok(true),
Some(ValidTypes::Undo) => Ok(single_object(input.object())?.is_kind("Follow")),
_ => 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
2020-05-21 21:24:56 +00:00
fn kind_str(base: &AnyBase) -> Result<&str, MyError> {
base.kind_str().ok_or(MyError::MissingKind)
}
2020-06-20 04:11:02 +00:00
fn id_string(id: Option<&Url>) -> Result<String, MyError> {
2020-05-21 21:24:56 +00:00
id.map(|s| s.to_string()).ok_or(MyError::MissingId)
}
fn single_object(o: &OneOrMany<AnyBase>) -> Result<&AnyBase, MyError> {
o.as_one().ok_or(MyError::ObjectCount)
}
async fn handle_accept(config: &Config, input: AcceptedActivities) -> Result<(), MyError> {
let base = single_object(input.object())?.clone();
let follow = if let Some(follow) = activity::Follow::from_any_base(base)? {
2020-05-21 21:24:56 +00:00
follow
} else {
return Err(MyError::Kind(
2020-05-21 21:24:56 +00:00
kind_str(single_object(input.object())?)?.to_owned(),
));
2020-05-21 21:24:56 +00:00
};
if !follow.actor_is(&config.generate_url(UrlKind::Actor)) {
2020-05-22 02:15:20 +00:00
return Err(MyError::WrongActor(id_string(
2020-06-20 04:11:02 +00:00
follow.actor()?.as_single_id(),
2020-05-22 02:15:20 +00:00
)?));
}
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,
2020-03-30 17:10:04 +00:00
) -> Result<(), MyError> {
let base = single_object(input.object())?.clone();
let follow = if let Some(follow) = activity::Follow::from_any_base(base)? {
2020-05-21 21:24:56 +00:00
follow
} else {
return Err(MyError::Kind(
2020-05-21 21:24:56 +00:00
kind_str(single_object(input.object())?)?.to_owned(),
));
2020-05-21 21:24:56 +00:00
};
if !follow.actor_is(&config.generate_url(UrlKind::Actor)) {
2020-05-22 02:15:20 +00:00
return Err(MyError::WrongActor(id_string(
2020-06-20 04:11:02 +00:00
follow.actor()?.as_single_id(),
2020-05-22 02:15:20 +00:00
)?));
}
2020-03-30 17:10:04 +00:00
jobs.queue(Reject(actor))?;
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,
2020-03-30 17:10:04 +00:00
) -> Result<(), MyError> {
2020-05-21 21:24:56 +00:00
let any_base = single_object(input.object())?.clone();
let undone_object =
AcceptedUndoObjects::from_any_base(any_base)?.ok_or(MyError::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 {
2020-03-30 17:10:04 +00:00
jobs.queue(Forward::new(input, actor))?;
return Ok(());
} else {
return Err(MyError::NotSubscribed(actor.inbox.to_string()));
}
2020-03-15 22:37:53 +00:00
}
2020-06-20 04:11:02 +00:00
let my_id: Url = 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()) {
2020-05-22 02:15:20 +00:00
return Err(MyError::WrongActor(id_string(
undone_object.object().as_single_id(),
)?));
}
if !is_listener {
2020-03-30 17:10:04 +00:00
return Ok(());
2020-03-23 22:17:53 +00:00
}
2020-03-30 17:10:04 +00:00
jobs.queue(Undo::new(input, actor))?;
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,
2020-03-30 17:10:04 +00:00
) -> Result<(), MyError> {
jobs.queue(Forward::new(input, actor))?;
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,
2020-03-30 17:10:04 +00:00
) -> Result<(), MyError> {
2020-05-21 21:24:56 +00:00
let object_id = input.object().as_single_id().ok_or(MyError::MissingId)?;
2020-03-15 22:37:53 +00:00
if state.is_cached(object_id).await {
2020-03-16 03:36:46 +00:00
return Err(MyError::Duplicate);
2020-03-15 22:37:53 +00:00
}
2020-03-30 17:10:04 +00:00
jobs.queue(Announce::new(object_id.to_owned(), actor))?;
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,
2020-03-18 05:43:31 +00:00
is_listener: bool,
2020-03-30 17:10:04 +00:00
) -> Result<(), MyError> {
2020-06-20 04:11:02 +00:00
let my_id: Url = 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()) {
return Err(MyError::WrongActor(id_string(
input.object().as_single_id(),
)?));
2020-03-15 17:49:27 +00:00
}
2020-03-30 17:10:04 +00:00
jobs.queue(Follow::new(is_listener, input, actor))?;
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
}