hyaenidae/profiles/src/apub/actions/apub/like.rs
asonix 83b447b780 Profiles: Federation fixes
- Fix image federation
- Enable submission & comment create/update federation
- Improve checks to ensure we don't federate when we don't need to
2021-01-17 15:01:45 -06:00

130 lines
4 KiB
Rust

use crate::{
apub::actions::{apub::require_federation, CreateReact, DeleteReact},
recover, Action, Context, Error, KeyOwner, RecoverableError, Required,
};
use activitystreams::prelude::*;
pub(crate) fn like(
like: &activitystreams::activity::Like,
key_owner: Option<KeyOwner>,
ctx: &Context,
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
let like_id = like.id_unchecked().req("like id")?;
// Double create
if ctx.apub.object(like_id)?.is_some() {
return Err(Error::Invalid);
}
let actor = like.actor()?.as_single_id().req("like actor id")?;
require_federation(key_owner, actor, ctx)?;
let object = like.object().as_single_id().req("like object id")?;
let react = like
.content()
.req("content")?
.as_single_xsd_string()
.req("content string")?;
let published = like.published().req("published")?;
let actor_id = recover!(actor, ctx.apub.id_for_apub(actor)?);
let actor_id = actor_id.profile().req("like actor id as profile id")?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor_id)? {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
return Err(Error::Invalid);
}
let object_id = recover!(object, ctx.apub.id_for_apub(object)?);
if let Some(submission_id) = object_id.submission() {
return Ok(Ok(Box::new(CreateReact {
like_apub_id: Some(like_id.to_owned()),
submission_id,
profile_id: actor_id,
comment_id: None,
react: react.to_owned(),
published: published.into(),
})));
}
if let Some(comment_id) = object_id.comment() {
let submission_id = ctx
.store
.comments
.by_id(comment_id)?
.req("comment by id")?
.submission_id();
return Ok(Ok(Box::new(CreateReact {
like_apub_id: Some(like_id.to_owned()),
submission_id,
profile_id: actor_id,
comment_id: Some(comment_id),
react: react.to_owned(),
published: published.into(),
})));
}
Err(Error::Invalid)
}
pub(crate) fn undo_like(
undo: &activitystreams::activity::Undo,
like: &activitystreams::activity::Like,
key_owner: Option<KeyOwner>,
ctx: &Context,
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
let like_id = like.id_unchecked().req("like id")?;
let undo_actor_id = undo.actor()?.as_single_id().req("undo actor id")?;
require_federation(key_owner, undo_actor_id, ctx)?;
let actor_id = like.actor()?.as_single_id().req("like actor id")?;
if undo_actor_id != actor_id {
return Err(Error::Invalid);
}
let actor_id = recover!(actor_id, ctx.apub.id_for_apub(actor_id)?);
let actor_id = actor_id.profile().req("like actor id as profile id")?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor_id)? {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
return Err(Error::Invalid);
}
let object_id = like.object().as_single_id().req("like object id")?;
let object_id = recover!(object_id, ctx.apub.id_for_apub(object_id)?);
let react_id = recover!(like_id, ctx.apub.id_for_apub(like_id)?);
let react_id = react_id.react().req("like id as react id")?;
let react = ctx.store.reacts.by_id(react_id)?.req("react by id")?;
if react.profile_id() != actor_id {
return Err(Error::Invalid);
}
if let Some(comment_id) = react.comment_id() {
let object_id = object_id.comment().req("like object id as comment id")?;
if comment_id != object_id {
return Err(Error::Invalid);
}
} else {
let object_id = object_id
.submission()
.req("like object id as submission id")?;
if react.submission_id() != object_id {
return Err(Error::Invalid);
}
}
Ok(Ok(Box::new(DeleteReact { react_id })))
}