]> Untitled Git - lemmy.git/commitdiff
Add method verify_activity_domains_valid() (ref #1196)
authorFelix Ableitner <me@nutomic.com>
Wed, 14 Oct 2020 15:34:11 +0000 (17:34 +0200)
committerFelix Ableitner <me@nutomic.com>
Thu, 15 Oct 2020 13:38:03 +0000 (15:38 +0200)
14 files changed:
docs/src/contributing_apub_api_outline.md
lemmy_apub/src/activities/receive/mod.rs
lemmy_apub/src/extensions/signatures.rs
lemmy_apub/src/fetcher.rs
lemmy_apub/src/inbox/community_inbox.rs
lemmy_apub/src/inbox/shared_inbox.rs
lemmy_apub/src/inbox/user_inbox.rs
lemmy_apub/src/lib.rs
lemmy_apub/src/objects/comment.rs
lemmy_apub/src/objects/community.rs
lemmy_apub/src/objects/mod.rs
lemmy_apub/src/objects/post.rs
lemmy_apub/src/objects/private_message.rs
lemmy_apub/src/objects/user.rs

index ae7f21cf62691e5dbd1b4df9d84a9e9ecf2f0474..af3eb0f2d74928cbb7a38e50f04a6ed30a9cbdf5 100644 (file)
@@ -597,7 +597,7 @@ Sent to: User
     "type": "Delete",
     "actor": "https://ds9.lemmy.ml/u/sisko",
     "to": "https://enterprise.lemmy.ml/u/riker/inbox",
-    "object": "https://enterprise.lemmy.ml/private_message/341"
+    "object": "https://ds9.lemmy.ml/private_message/341"
 }
 ```
 
index 730454b4eed9ef76b0201f07ffc2dd235afe5790..ab830ca79ca2289b29b4e0c182e7649b1cc9bb2a 100644 (file)
@@ -4,7 +4,8 @@ use crate::{
 };
 use activitystreams::{
   activity::{ActorAndObjectRef, ActorAndObjectRefExt},
-  base::{AsBase, Extends, ExtendsExt},
+  base::{AsBase, BaseExt, Extends, ExtendsExt},
+  error::DomainError,
   object::{AsObject, ObjectExt},
 };
 use actix_web::HttpResponse;
@@ -121,3 +122,36 @@ pub(crate) async fn find_by_id(
 
   return Err(NotFound.into());
 }
+
+pub(crate) fn verify_activity_domains_valid<T, Kind>(
+  activity: &T,
+  actor_id: Url,
+  object_domain_must_match: bool,
+) -> Result<(), LemmyError>
+where
+  T: AsBase<Kind> + ActorAndObjectRef,
+{
+  let expected_domain = actor_id.domain().context(location_info!())?;
+
+  activity.id(expected_domain)?;
+
+  let object_id = match activity.object().to_owned().single_xsd_any_uri() {
+    // object is just an ID
+    Some(id) => id,
+    // object is something like an activity, a comment or a post
+    None => activity
+      .object()
+      .to_owned()
+      .one()
+      .context(location_info!())?
+      .id()
+      .context(location_info!())?
+      .to_owned(),
+  };
+
+  if object_domain_must_match && object_id.domain() != Some(expected_domain) {
+    return Err(DomainError.into());
+  }
+
+  Ok(())
+}
index cdcb707a68aac3dfe91504925b23a3bf46b8aa0b..8e8c31e4dab05e86e60b3c96e219a56ec7828d8c 100644 (file)
@@ -63,7 +63,7 @@ pub async fn sign_and_send(
   Ok(response)
 }
 
-pub fn verify(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> {
+pub fn verify_signature(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> {
   let public_key = actor.public_key().context(location_info!())?;
   let verified = CONFIG2
     .begin_verify(
index bd85ddc8eaf0c93916fc269579352fbbe47ff199..986c9dd470ac93396715b25be56e351a1401c64c 100644 (file)
@@ -93,7 +93,7 @@ pub async fn search_by_apub_id(
 ) -> Result<SearchResponse, LemmyError> {
   // Parse the shorthand query url
   let query_url = if query.contains('@') {
-    debug!("{}", query);
+    debug!("Search for {}", query);
     let split = query.split('@').collect::<Vec<&str>>();
 
     // User type will look like ['', username, instance]
index 5def86c22f9a2d3904c6b9855b333ce80a6f0279..2c36c684089bef0eb1ab4c4361c4f3b0308641cc 100644 (file)
@@ -1,6 +1,7 @@
 use crate::{
+  activities::receive::verify_activity_domains_valid,
   check_is_apub_id_valid,
-  extensions::signatures::verify,
+  extensions::signatures::verify_signature,
   fetcher::get_or_fetch_and_upsert_user,
   insert_activity,
   ActorType,
@@ -48,15 +49,15 @@ pub async fn community_inbox(
   })
   .await??;
 
-  if !community.local {
-    return Err(
-      anyhow!(
-        "Received activity is addressed to remote community {}",
-        &community.actor_id
-      )
-      .into(),
-    );
+  let to = activity
+    .to()
+    .context(location_info!())?
+    .to_owned()
+    .single_xsd_any_uri();
+  if Some(community.actor_id()?) != to {
+    return Err(anyhow!("Activity delivered to wrong community").into());
   }
+
   info!(
     "Community {} received activity {:?}",
     &community.name, &activity
@@ -75,7 +76,7 @@ pub async fn community_inbox(
 
   let user = get_or_fetch_and_upsert_user(&user_uri, &context).await?;
 
-  verify(&request, &user)?;
+  verify_signature(&request, &user)?;
 
   let any_base = activity.clone().into_any_base()?;
   let kind = activity.kind().context(location_info!())?;
@@ -98,6 +99,8 @@ async fn handle_follow(
   context: &LemmyContext,
 ) -> Result<HttpResponse, LemmyError> {
   let follow = Follow::from_any_base(activity)?.context(location_info!())?;
+  verify_activity_domains_valid(&follow, user.actor_id()?, false)?;
+
   let community_follower_form = CommunityFollowerForm {
     community_id: community.id,
     user_id: user.id,
@@ -120,7 +123,12 @@ async fn handle_undo_follow(
   community: Community,
   context: &LemmyContext,
 ) -> Result<HttpResponse, LemmyError> {
-  let _undo = Undo::from_any_base(activity)?.context(location_info!())?;
+  let undo = Undo::from_any_base(activity)?.context(location_info!())?;
+  verify_activity_domains_valid(&undo, user.actor_id()?, true)?;
+
+  let object = undo.object().to_owned().one().context(location_info!())?;
+  let follow = Follow::from_any_base(object)?.context(location_info!())?;
+  verify_activity_domains_valid(&follow, user.actor_id()?, false)?;
 
   let community_follower_form = CommunityFollowerForm {
     community_id: community.id,
index 5b87e0f89bf3ade91e53c463f467cb056b4905ba..cdaa0e8fb9dfa7d0fce9ede85b8d87b79c0cb81e 100644 (file)
@@ -10,7 +10,7 @@ use crate::{
     update::receive_update,
   },
   check_is_apub_id_valid,
-  extensions::signatures::verify,
+  extensions::signatures::verify_signature,
   fetcher::get_or_fetch_and_upsert_actor,
   insert_activity,
 };
@@ -62,7 +62,7 @@ pub async fn shared_inbox(
   check_is_apub_id_valid(&actor)?;
 
   let actor = get_or_fetch_and_upsert_actor(&actor, &context).await?;
-  verify(&request, actor.as_ref())?;
+  verify_signature(&request, actor.as_ref())?;
 
   let any_base = activity.clone().into_any_base()?;
   let kind = activity.kind().context(location_info!())?;
index 7bc36a0ff70d70eb195adec8c9a30dd078ebadae..2ee6d6edf46e86172c1f9dc0ac1a7c761a46e3b3 100644 (file)
@@ -1,19 +1,20 @@
 use crate::{
+  activities::receive::verify_activity_domains_valid,
   check_is_apub_id_valid,
-  extensions::signatures::verify,
+  extensions::signatures::verify_signature,
   fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_community},
   insert_activity,
+  ActorType,
   FromApub,
 };
 use activitystreams::{
-  activity::{Accept, ActorAndObject, Create, Delete, Undo, Update},
+  activity::{Accept, ActorAndObject, Create, Delete, Follow, Undo, Update},
   base::AnyBase,
-  error::DomainError,
   object::Note,
   prelude::*,
 };
 use actix_web::{web, HttpRequest, HttpResponse};
-use anyhow::Context;
+use anyhow::{anyhow, Context};
 use lemmy_db::{
   community::{CommunityFollower, CommunityFollowerForm},
   private_message::{PrivateMessage, PrivateMessageForm},
@@ -50,6 +51,19 @@ pub async fn user_inbox(
 ) -> Result<HttpResponse, LemmyError> {
   let activity = input.into_inner();
   let username = path.into_inner();
+  let user = blocking(&context.pool(), move |conn| {
+    User_::read_from_name(&conn, &username)
+  })
+  .await??;
+
+  let to = activity
+    .to()
+    .context(location_info!())?
+    .to_owned()
+    .single_xsd_any_uri();
+  if Some(user.actor_id()?) != to {
+    return Err(anyhow!("Activity delivered to wrong user").into());
+  }
 
   let actor_uri = activity
     .actor()?
@@ -57,7 +71,7 @@ pub async fn user_inbox(
     .context(location_info!())?;
   debug!(
     "User {} inbox received activity {:?} from {}",
-    username,
+    user.name,
     &activity.id_unchecked(),
     &actor_uri
   );
@@ -65,16 +79,18 @@ pub async fn user_inbox(
   check_is_apub_id_valid(actor_uri)?;
 
   let actor = get_or_fetch_and_upsert_actor(actor_uri, &context).await?;
-  verify(&request, actor.as_ref())?;
+  verify_signature(&request, actor.as_ref())?;
 
   let any_base = activity.clone().into_any_base()?;
   let kind = activity.kind().context(location_info!())?;
   let res = match kind {
-    ValidTypes::Accept => receive_accept(any_base, username, &context).await,
-    ValidTypes::Create => receive_create_private_message(any_base, &context).await,
-    ValidTypes::Update => receive_update_private_message(any_base, &context).await,
-    ValidTypes::Delete => receive_delete_private_message(any_base, &context).await,
-    ValidTypes::Undo => receive_undo_delete_private_message(any_base, &context).await,
+    ValidTypes::Accept => receive_accept(&context, any_base, actor.as_ref(), user).await,
+    ValidTypes::Create => receive_create_private_message(&context, any_base, actor.as_ref()).await,
+    ValidTypes::Update => receive_update_private_message(&context, any_base, actor.as_ref()).await,
+    ValidTypes::Delete => receive_delete_private_message(&context, any_base, actor.as_ref()).await,
+    ValidTypes::Undo => {
+      receive_undo_delete_private_message(&context, any_base, actor.as_ref()).await
+    }
   };
 
   insert_activity(actor.user_id(), activity.clone(), false, context.pool()).await?;
@@ -83,11 +99,20 @@ pub async fn user_inbox(
 
 /// Handle accepted follows.
 async fn receive_accept(
-  activity: AnyBase,
-  username: String,
   context: &LemmyContext,
+  activity: AnyBase,
+  actor: &dyn ActorType,
+  user: User_,
 ) -> Result<HttpResponse, LemmyError> {
   let accept = Accept::from_any_base(activity)?.context(location_info!())?;
+  verify_activity_domains_valid(&accept, actor.actor_id()?, false)?;
+
+  // TODO: we should check that we actually sent this activity, because the remote instance
+  //       could just put a fake Follow
+  let object = accept.object().to_owned().one().context(location_info!())?;
+  let follow = Follow::from_any_base(object)?.context(location_info!())?;
+  verify_activity_domains_valid(&follow, user.actor_id()?, false)?;
+
   let community_uri = accept
     .actor()?
     .to_owned()
@@ -96,11 +121,6 @@ async fn receive_accept(
 
   let community = get_or_fetch_and_upsert_community(&community_uri, context).await?;
 
-  let user = blocking(&context.pool(), move |conn| {
-    User_::read_from_name(conn, &username)
-  })
-  .await??;
-
   // Now you need to add this to the community follower
   let community_follower_form = CommunityFollowerForm {
     community_id: community.id,
@@ -113,15 +133,17 @@ async fn receive_accept(
   })
   .await?;
 
-  // TODO: make sure that we actually requested a follow
   Ok(HttpResponse::Ok().finish())
 }
 
 async fn receive_create_private_message(
-  activity: AnyBase,
   context: &LemmyContext,
+  activity: AnyBase,
+  actor: &dyn ActorType,
 ) -> Result<HttpResponse, LemmyError> {
   let create = Create::from_any_base(activity)?.context(location_info!())?;
+  verify_activity_domains_valid(&create, actor.actor_id()?, true)?;
+
   let note = Note::from_any_base(
     create
       .object()
@@ -131,18 +153,8 @@ async fn receive_create_private_message(
   )?
   .context(location_info!())?;
 
-  let actor = create
-    .actor()?
-    .to_owned()
-    .single_xsd_any_uri()
-    .context(location_info!())?;
-  let domain = Some(
-    create
-      .id(actor.domain().context(location_info!())?)?
-      .context(location_info!())?
-      .to_owned(),
-  );
-  let private_message = PrivateMessageForm::from_apub(&note, context, domain).await?;
+  let private_message =
+    PrivateMessageForm::from_apub(&note, context, Some(actor.actor_id()?)).await?;
 
   let inserted_private_message = blocking(&context.pool(), move |conn| {
     PrivateMessage::create(conn, &private_message)
@@ -169,31 +181,22 @@ async fn receive_create_private_message(
 }
 
 async fn receive_update_private_message(
-  activity: AnyBase,
   context: &LemmyContext,
+  activity: AnyBase,
+  actor: &dyn ActorType,
 ) -> Result<HttpResponse, LemmyError> {
   let update = Update::from_any_base(activity)?.context(location_info!())?;
-  let note = Note::from_any_base(
-    update
-      .object()
-      .as_one()
-      .context(location_info!())?
-      .to_owned(),
-  )?
-  .context(location_info!())?;
+  verify_activity_domains_valid(&update, actor.actor_id()?, true)?;
 
-  let actor = update
-    .actor()?
-    .to_owned()
-    .single_xsd_any_uri()
-    .context(location_info!())?;
-  let domain = Some(
-    update
-      .id(actor.domain().context(location_info!())?)?
-      .context(location_info!())?
-      .to_owned(),
-  );
-  let private_message_form = PrivateMessageForm::from_apub(&note, context, domain).await?;
+  let object = update
+    .object()
+    .as_one()
+    .context(location_info!())?
+    .to_owned();
+  let note = Note::from_any_base(object)?.context(location_info!())?;
+
+  let private_message_form =
+    PrivateMessageForm::from_apub(&note, context, Some(actor.actor_id()?)).await?;
 
   let private_message_ap_id = private_message_form
     .ap_id
@@ -232,27 +235,18 @@ async fn receive_update_private_message(
 }
 
 async fn receive_delete_private_message(
-  activity: AnyBase,
   context: &LemmyContext,
+  activity: AnyBase,
+  actor: &dyn ActorType,
 ) -> Result<HttpResponse, LemmyError> {
   let delete = Delete::from_any_base(activity)?.context(location_info!())?;
+  verify_activity_domains_valid(&delete, actor.actor_id()?, true)?;
+
   let private_message_id = delete
     .object()
     .to_owned()
     .single_xsd_any_uri()
     .context(location_info!())?;
-  let actor = delete
-    .actor()?
-    .to_owned()
-    .single_xsd_any_uri()
-    .context(location_info!())?;
-  let delete_id = delete
-    .id(actor.domain().context(location_info!())?)?
-    .map(|i| i.domain())
-    .flatten();
-  if private_message_id.domain() != delete_id {
-    return Err(DomainError.into());
-  }
   let private_message = blocking(context.pool(), move |conn| {
     PrivateMessage::read_from_apub_id(conn, private_message_id.as_str())
   })
@@ -280,30 +274,21 @@ async fn receive_delete_private_message(
 }
 
 async fn receive_undo_delete_private_message(
-  activity: AnyBase,
   context: &LemmyContext,
+  activity: AnyBase,
+  actor: &dyn ActorType,
 ) -> Result<HttpResponse, LemmyError> {
   let undo = Undo::from_any_base(activity)?.context(location_info!())?;
-  let delete = Delete::from_any_base(undo.object().as_one().context(location_info!())?.to_owned())?
-    .context(location_info!())?;
+  verify_activity_domains_valid(&undo, actor.actor_id()?, true)?;
+  let object = undo.object().to_owned().one().context(location_info!())?;
+  let delete = Delete::from_any_base(object)?.context(location_info!())?;
+  verify_activity_domains_valid(&delete, actor.actor_id()?, true)?;
+
   let private_message_id = delete
     .object()
     .to_owned()
     .single_xsd_any_uri()
     .context(location_info!())?;
-  let actor = undo
-    .actor()?
-    .to_owned()
-    .single_xsd_any_uri()
-    .context(location_info!())?;
-  let undo_id = undo
-    .id(actor.domain().context(location_info!())?)?
-    .map(|i| i.domain())
-    .flatten();
-  if private_message_id.domain() != undo_id {
-    return Err(DomainError.into());
-  }
-
   let private_message = blocking(context.pool(), move |conn| {
     PrivateMessage::read_from_apub_id(conn, private_message_id.as_str())
   })
@@ -319,9 +304,7 @@ async fn receive_undo_delete_private_message(
   .await??;
 
   let res = PrivateMessageResponse { message };
-
   let recipient_id = res.message.recipient_id;
-
   context.chat_server().do_send(SendUserRoomMessage {
     op: UserOperation::EditPrivateMessage,
     response: res,
index d088447e860a4b8b0ff8fa68f809283931f3f942..4c8f962207c45c36a28ea39d853a647f27131679 100644 (file)
@@ -17,10 +17,8 @@ use crate::extensions::{
 use activitystreams::{
   activity::Follow,
   actor::{ApActor, Group, Person},
-  base::{AnyBase, AsBase},
-  markers::Base,
+  base::AnyBase,
   object::{Page, Tombstone},
-  prelude::*,
 };
 use activitystreams_ext::{Ext1, Ext2};
 use anyhow::{anyhow, Context};
@@ -132,24 +130,6 @@ pub trait ApubObjectType {
   async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError>;
 }
 
-pub(in crate) fn check_actor_domain<T, Kind>(
-  apub: &T,
-  expected_domain: Option<Url>,
-) -> Result<String, LemmyError>
-where
-  T: Base + AsBase<Kind>,
-{
-  let actor_id = if let Some(url) = expected_domain {
-    let domain = url.domain().context(location_info!())?;
-    apub.id(domain)?.context(location_info!())?
-  } else {
-    let actor_id = apub.id_unchecked().context(location_info!())?;
-    check_is_apub_id_valid(&actor_id)?;
-    actor_id
-  };
-  Ok(actor_id.to_string())
-}
-
 #[async_trait::async_trait(?Send)]
 pub trait ApubLikeableType {
   async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError>;
index 22f22f8803322f7c358f6047b44e16ba3a62964d..537ab958e7d4077a3947438a866dc5c7ab224a53 100644 (file)
@@ -1,11 +1,10 @@
 use crate::{
-  check_actor_domain,
   fetcher::{
     get_or_fetch_and_insert_comment,
     get_or_fetch_and_insert_post,
     get_or_fetch_and_upsert_user,
   },
-  objects::create_tombstone,
+  objects::{check_object_domain, create_tombstone},
   FromApub,
   ToApub,
 };
@@ -140,7 +139,7 @@ impl FromApub for CommentForm {
       published: note.published().map(|u| u.to_owned().naive_local()),
       updated: note.updated().map(|u| u.to_owned().naive_local()),
       deleted: None,
-      ap_id: Some(check_actor_domain(note, expected_domain)?),
+      ap_id: Some(check_object_domain(note, expected_domain)?),
       local: false,
     })
   }
index 0318171811b8406cb6c8f61135e89bcd2184b74b..cf221fa2f3372a4e651d9d6262d30d74ec5c0896 100644 (file)
@@ -1,8 +1,7 @@
 use crate::{
-  check_actor_domain,
   extensions::group_extensions::GroupExtension,
   fetcher::get_or_fetch_and_upsert_user,
-  objects::create_tombstone,
+  objects::{check_object_domain, create_tombstone},
   ActorType,
   FromApub,
   GroupExt,
@@ -189,7 +188,7 @@ impl FromApub for CommunityForm {
       updated: group.inner.updated().map(|u| u.to_owned().naive_local()),
       deleted: None,
       nsfw: group.ext_one.sensitive,
-      actor_id: Some(check_actor_domain(group, expected_domain)?),
+      actor_id: Some(check_object_domain(group, expected_domain)?),
       local: false,
       private_key: None,
       public_key: Some(group.ext_two.to_owned().public_key.public_key_pem),
index f3a701c2f4c450a8f6cb71a07dcf86aa1f50bffe..56d02607cb8d400f9f7f3e990c50633c2f393522 100644 (file)
@@ -1,10 +1,13 @@
+use crate::check_is_apub_id_valid;
 use activitystreams::{
-  base::BaseExt,
+  base::{AsBase, BaseExt},
+  markers::Base,
   object::{Tombstone, TombstoneExt},
 };
-use anyhow::anyhow;
+use anyhow::{anyhow, Context};
 use chrono::NaiveDateTime;
-use lemmy_utils::{utils::convert_datetime, LemmyError};
+use lemmy_utils::{location_info, utils::convert_datetime, LemmyError};
+use url::Url;
 
 pub mod comment;
 pub mod community;
@@ -36,3 +39,22 @@ where
     Err(anyhow!("Cant convert object to tombstone if it wasnt deleted").into())
   }
 }
+
+pub(in crate::objects) fn check_object_domain<T, Kind>(
+  apub: &T,
+  expected_domain: Option<Url>,
+) -> Result<String, LemmyError>
+where
+  T: Base + AsBase<Kind>,
+{
+  let actor_id = if let Some(url) = expected_domain {
+    check_is_apub_id_valid(&url)?;
+    let domain = url.domain().context(location_info!())?;
+    apub.id(domain)?.context(location_info!())?
+  } else {
+    let actor_id = apub.id_unchecked().context(location_info!())?;
+    check_is_apub_id_valid(&actor_id)?;
+    actor_id
+  };
+  Ok(actor_id.to_string())
+}
index 3a979f5e16fc6af5b35e05516c12c6ed58ef45a0..0c1aaf297bef6265326af044fc262f7b47b9101f 100644 (file)
@@ -1,8 +1,7 @@
 use crate::{
-  check_actor_domain,
   extensions::page_extension::PageExtension,
   fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user},
-  objects::create_tombstone,
+  objects::{check_object_domain, create_tombstone},
   FromApub,
   PageExt,
   ToApub,
@@ -193,7 +192,7 @@ impl FromApub for PostForm {
       embed_description: iframely_description,
       embed_html: iframely_html,
       thumbnail_url: pictrs_thumbnail,
-      ap_id: Some(check_actor_domain(page, expected_domain)?),
+      ap_id: Some(check_object_domain(page, expected_domain)?),
       local: false,
     })
   }
index cc01bccb8173cf79f973f6ce915af23305cdd42c..413ab22f4a10a3301128f05bb976b83d2ee758f1 100644 (file)
@@ -1,8 +1,7 @@
 use crate::{
-  check_actor_domain,
   check_is_apub_id_valid,
   fetcher::get_or_fetch_and_upsert_user,
-  objects::create_tombstone,
+  objects::{check_object_domain, create_tombstone},
   FromApub,
   ToApub,
 };
@@ -96,7 +95,7 @@ impl FromApub for PrivateMessageForm {
       updated: note.updated().map(|u| u.to_owned().naive_local()),
       deleted: None,
       read: None,
-      ap_id: Some(check_actor_domain(note, expected_domain)?),
+      ap_id: Some(check_object_domain(note, expected_domain)?),
       local: false,
     })
   }
index 96ece96865539f49acf89ac8b1327e95fc4b989b..ef314775f2a77f780c69bb1d1ccea7ff48198e29 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{check_actor_domain, ActorType, FromApub, PersonExt, ToApub};
+use crate::{objects::check_object_domain, ActorType, FromApub, PersonExt, ToApub};
 use activitystreams::{
   actor::{ApActor, Endpoints, Person},
   object::{Image, Tombstone},
@@ -145,7 +145,7 @@ impl FromApub for UserForm {
       show_avatars: false,
       send_notifications_to_email: false,
       matrix_user_id: None,
-      actor_id: Some(check_actor_domain(person, expected_domain)?),
+      actor_id: Some(check_object_domain(person, expected_domain)?),
       bio: Some(bio),
       local: false,
       private_key: None,