diff --git a/src/activitypub/receiver.rs b/src/activitypub/receiver.rs index 233f717..627a4a5 100644 --- a/src/activitypub/receiver.rs +++ b/src/activitypub/receiver.rs @@ -9,7 +9,7 @@ use crate::config::{Config, Instance}; use crate::database::{Pool, get_database_client}; use crate::errors::{DatabaseError, HttpError, ValidationError}; use crate::models::attachments::queries::create_attachment; -use crate::models::posts::types::{Post, PostCreateData, Visibility}; +use crate::models::posts::mentions::mention_to_acct; use crate::models::posts::queries::{ create_post, get_post_by_id, @@ -17,6 +17,7 @@ use crate::models::posts::queries::{ delete_post, }; use crate::models::posts::tags::normalize_tag; +use crate::models::posts::types::{Post, PostCreateData, Visibility}; use crate::models::profiles::queries::{ get_profile_by_actor_id, get_profile_by_acct, @@ -241,13 +242,9 @@ pub async fn process_note( tags.push(tag_name); }; } else if tag.tag_type == MENTION { - if let Some(href) = tag.href { - let profile = get_or_fetch_profile_by_actor_id( - db_client, - &instance, - &href, - &config.media_dir(), - ).await?; + // Ignore invalid mentions + if let Ok(acct) = mention_to_acct(&instance.host(), &tag.name) { + let profile = get_profile_by_acct(db_client, &acct).await?; if !mentions.contains(&profile.id) { mentions.push(profile.id); }; diff --git a/src/models/posts/mentions.rs b/src/models/posts/mentions.rs index 1a40222..9bd3fbe 100644 --- a/src/models/posts/mentions.rs +++ b/src/models/posts/mentions.rs @@ -3,11 +3,12 @@ use std::collections::HashMap; use regex::{Captures, Regex}; use tokio_postgres::GenericClient; -use crate::errors::DatabaseError; +use crate::errors::{DatabaseError, ValidationError}; use crate::models::profiles::queries::get_profiles_by_accts; use crate::models::profiles::types::DbActorProfile; -const MENTION_RE: &str = r"(?m)(?P^|\s)@(?P\w+)@(?P\S+)"; +const MENTION_RE: &str = r"@?(?P\w+)@(?P.+)"; +const MENTION_SEARCH_RE: &str = r"(?m)(?P^|\s)@(?P\w+)@(?P\S+)"; fn pattern_to_acct(caps: &Captures, instance_host: &str) -> String { if &caps["instance"] == instance_host { @@ -22,7 +23,7 @@ fn find_mentions( instance_host: &str, text: &str, ) -> Vec { - let mention_re = Regex::new(MENTION_RE).unwrap(); + let mention_re = Regex::new(MENTION_SEARCH_RE).unwrap(); let mut mentions = vec![]; for caps in mention_re.captures_iter(text) { let acct = pattern_to_acct(&caps, instance_host); @@ -53,12 +54,13 @@ pub fn replace_mentions( instance_url: &str, text: &str, ) -> String { - let mention_re = Regex::new(MENTION_RE).unwrap(); + let mention_re = Regex::new(MENTION_SEARCH_RE).unwrap(); let result = mention_re.replace_all(text, |caps: &Captures| { let acct = pattern_to_acct(caps, instance_host); match mention_map.get(&acct) { Some(profile) => { - // Replace with a link + // Replace with a link to profile. + // Actor URL may differ from actor ID. let url = profile.actor_url(instance_url).unwrap(); format!( // https://microformats.org/wiki/h-card @@ -74,6 +76,17 @@ pub fn replace_mentions( result.to_string() } +pub fn mention_to_acct( + instance_host: &str, + mention: &str, +) -> Result { + let mention_re = Regex::new(MENTION_RE).unwrap(); + let mention_caps = mention_re.captures(mention) + .ok_or(ValidationError("invalid mention tag"))?; + let acct = pattern_to_acct(&mention_caps, instance_host); + Ok(acct) +} + #[cfg(test)] mod tests { use serde_json::json; @@ -131,4 +144,14 @@ mod tests { ); assert_eq!(result, expected_result); } + + #[test] + fn test_mention_to_acct() { + let mention = "@user@example.com"; + let acct_1 = mention_to_acct("example.com", mention).unwrap(); + assert_eq!(acct_1, "user"); + + let acct_2 = mention_to_acct("server.info", mention).unwrap(); + assert_eq!(acct_2, "user@example.com"); + } } diff --git a/src/models/posts/tags.rs b/src/models/posts/tags.rs index 04f067b..05091ab 100644 --- a/src/models/posts/tags.rs +++ b/src/models/posts/tags.rs @@ -1,6 +1,6 @@ use regex::{Captures, Regex}; -use crate::errors::ConversionError; +use crate::errors::ValidationError; use crate::frontend::get_tag_page_url; const HASHTAG_RE: &str = r"(?m)(?P^|\s)#(?P\S+)"; @@ -52,11 +52,11 @@ pub fn replace_tags(instance_url: &str, text: &str, tags: &[String]) -> String { result.to_string() } -pub fn normalize_tag(tag: &str) -> Result { +pub fn normalize_tag(tag: &str) -> Result { let hashtag_name_re = Regex::new(HASHTAG_NAME_RE).unwrap(); let tag_name = tag.trim_start_matches('#'); if !hashtag_name_re.is_match(tag_name) { - return Err(ConversionError); + return Err(ValidationError("invalid tag name")); }; Ok(tag_name.to_lowercase()) }