lemmy/server/src/apub/user_inbox.rs

120 lines
3.4 KiB
Rust
Raw Normal View History

2020-04-19 17:35:40 +00:00
use crate::apub::fetcher::{fetch_remote_community, fetch_remote_user};
use crate::apub::signatures::verify;
use crate::db::post::{Post, PostForm};
use crate::db::Crud;
use activitystreams::activity::{Accept, Create, Update};
use activitystreams::object::Page;
2020-04-19 17:35:40 +00:00
use actix_web::{web, HttpRequest, HttpResponse};
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::PgConnection;
use failure::Error;
2020-04-17 14:55:28 +00:00
use log::debug;
use serde::Deserialize;
2020-04-19 17:35:40 +00:00
use url::Url;
#[serde(untagged)]
2020-04-17 14:55:28 +00:00
#[derive(Deserialize, Debug)]
pub enum UserAcceptedObjects {
Create(Create),
Update(Update),
Accept(Accept),
}
2020-04-17 15:33:55 +00:00
/// Handler for all incoming activities to user inboxes.
pub async fn user_inbox(
2020-04-19 17:35:40 +00:00
request: HttpRequest,
input: web::Json<UserAcceptedObjects>,
2020-04-17 17:34:18 +00:00
path: web::Path<String>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
) -> Result<HttpResponse, Error> {
2020-04-19 17:35:40 +00:00
// TODO: would be nice if we could do the signature check here, but we cant access the actor property
let input = input.into_inner();
let conn = &db.get().unwrap();
2020-04-17 17:34:18 +00:00
debug!(
"User {} received activity: {:?}",
&path.into_inner(),
&input
);
2020-04-17 14:55:28 +00:00
match input {
2020-04-19 17:35:40 +00:00
UserAcceptedObjects::Create(c) => handle_create(&c, &request, conn),
UserAcceptedObjects::Update(u) => handle_update(&u, &request, conn),
UserAcceptedObjects::Accept(a) => handle_accept(&a, &request, conn),
}
}
2020-04-17 15:33:55 +00:00
/// Handle create activities and insert them in the database.
2020-04-19 17:35:40 +00:00
fn handle_create(
create: &Create,
request: &HttpRequest,
conn: &PgConnection,
) -> Result<HttpResponse, Error> {
let community_uri = create
.create_props
.get_actor_xsd_any_uri()
.unwrap()
.to_string();
// TODO: should do this in a generic way so we dont need to know if its a user or a community
let user = fetch_remote_user(&Url::parse(&community_uri)?, conn)?;
verify(request, &user.public_key.unwrap())?;
let page = create
.create_props
.get_object_base_box()
.to_owned()
.unwrap()
.to_owned()
.to_concrete::<Page>()?;
let post = PostForm::from_page(&page, conn)?;
Post::create(conn, &post)?;
// TODO: send the new post out via websocket
Ok(HttpResponse::Ok().finish())
}
2020-04-17 15:33:55 +00:00
/// Handle update activities and insert them in the database.
2020-04-19 17:35:40 +00:00
fn handle_update(
update: &Update,
request: &HttpRequest,
conn: &PgConnection,
) -> Result<HttpResponse, Error> {
let community_uri = update
.update_props
.get_actor_xsd_any_uri()
.unwrap()
.to_string();
let user = fetch_remote_user(&Url::parse(&community_uri)?, conn)?;
verify(request, &user.public_key.unwrap())?;
let page = update
.update_props
.get_object_base_box()
.to_owned()
.unwrap()
.to_owned()
.to_concrete::<Page>()?;
let post = PostForm::from_page(&page, conn)?;
let id = Post::read_from_apub_id(conn, &post.ap_id)?.id;
Post::update(conn, id, &post)?;
// TODO: send the new post out via websocket
Ok(HttpResponse::Ok().finish())
}
2020-04-17 15:33:55 +00:00
/// Handle accepted follows.
2020-04-19 17:35:40 +00:00
fn handle_accept(
accept: &Accept,
request: &HttpRequest,
conn: &PgConnection,
) -> Result<HttpResponse, Error> {
let community_uri = accept
.accept_props
.get_actor_xsd_any_uri()
.unwrap()
.to_string();
let community = fetch_remote_community(&Url::parse(&community_uri)?, conn)?;
verify(request, &community.public_key.unwrap())?;
2020-04-17 14:55:28 +00:00
// TODO: make sure that we actually requested a follow
// TODO: at this point, indicate to the user that they are following the community
Ok(HttpResponse::Ok().finish())
}