Rename instance field in ActorAddress to hostname

This commit is contained in:
silverpill 2022-10-09 14:26:58 +00:00
parent 0a62fdac2b
commit 81910f9591
8 changed files with 49 additions and 49 deletions

View file

@ -119,14 +119,14 @@ impl Actor {
pub fn address( pub fn address(
&self, &self,
) -> Result<ActorAddress, ValidationError> { ) -> Result<ActorAddress, ValidationError> {
let actor_host = url::Url::parse(&self.id) let hostname = url::Url::parse(&self.id)
.map_err(|_| ValidationError("invalid actor ID"))? .map_err(|_| ValidationError("invalid actor ID"))?
.host_str() .host_str()
.ok_or(ValidationError("invalid actor ID"))? .ok_or(ValidationError("invalid actor ID"))?
.to_owned(); .to_owned();
let actor_address = ActorAddress { let actor_address = ActorAddress {
username: self.preferred_username.clone(), username: self.preferred_username.clone(),
instance: actor_host, hostname: hostname,
}; };
Ok(actor_address) Ok(actor_address)
} }
@ -179,12 +179,12 @@ impl Actor {
pub struct ActorAddress { pub struct ActorAddress {
pub username: String, pub username: String,
pub instance: String, pub hostname: String,
} }
impl ActorAddress { impl ActorAddress {
pub fn is_local(&self, instance_host: &str) -> bool { pub fn is_local(&self, instance_host: &str) -> bool {
self.instance == instance_host self.hostname == instance_host
} }
/// Returns acct string, as used in Mastodon /// Returns acct string, as used in Mastodon
@ -198,7 +198,7 @@ impl ActorAddress {
} }
// See also: USERNAME_RE in models::profiles::validators // See also: USERNAME_RE in models::profiles::validators
pub const ACTOR_ADDRESS_RE: &str = r"(?P<username>[\w\.-]+)@(?P<instance>[\w\.-]+)"; pub const ACTOR_ADDRESS_RE: &str = r"(?P<username>[\w\.-]+)@(?P<hostname>[\w\.-]+)";
impl FromStr for ActorAddress { impl FromStr for ActorAddress {
type Err = ValidationError; type Err = ValidationError;
@ -209,7 +209,7 @@ impl FromStr for ActorAddress {
.ok_or(ValidationError("invalid actor address"))?; .ok_or(ValidationError("invalid actor address"))?;
let actor_address = Self { let actor_address = Self {
username: caps["username"].to_string(), username: caps["username"].to_string(),
instance: caps["instance"].to_string(), hostname: caps["hostname"].to_string(),
}; };
Ok(actor_address) Ok(actor_address)
} }
@ -217,7 +217,7 @@ impl FromStr for ActorAddress {
impl fmt::Display for ActorAddress { impl fmt::Display for ActorAddress {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}@{}", self.username, self.instance) write!(formatter, "{}@{}", self.username, self.hostname)
} }
} }
@ -357,7 +357,7 @@ mod tests {
let value = "user_1@example.com"; let value = "user_1@example.com";
let actor_address = value.parse::<ActorAddress>().unwrap(); let actor_address = value.parse::<ActorAddress>().unwrap();
assert_eq!(actor_address.username, "user_1"); assert_eq!(actor_address.username, "user_1");
assert_eq!(actor_address.instance, "example.com"); assert_eq!(actor_address.hostname, "example.com");
assert_eq!(actor_address.to_string(), value); assert_eq!(actor_address.to_string(), value);
} }

View file

@ -108,7 +108,7 @@ pub async fn perform_webfinger_query(
// TOOD: support http // TOOD: support http
let webfinger_url = format!( let webfinger_url = format!(
"https://{}/.well-known/webfinger", "https://{}/.well-known/webfinger",
actor_address.instance, actor_address.hostname,
); );
let client = build_client()?; let client = build_client()?;
let mut request_builder = client.get(&webfinger_url); let mut request_builder = client.get(&webfinger_url);

View file

@ -73,7 +73,7 @@ async fn create_remote_profile(
actor.parse_attachments(); actor.parse_attachments();
let mut profile_data = ProfileCreateData { let mut profile_data = ProfileCreateData {
username: actor.preferred_username.clone(), username: actor.preferred_username.clone(),
hostname: Some(actor_address.instance), hostname: Some(actor_address.hostname),
display_name: actor.name.clone(), display_name: actor.name.clone(),
bio: actor.summary.clone(), bio: actor.summary.clone(),
avatar, avatar,
@ -165,7 +165,7 @@ pub async fn import_profile_by_actor_address(
media_dir: &Path, media_dir: &Path,
actor_address: &ActorAddress, actor_address: &ActorAddress,
) -> Result<DbActorProfile, ImportError> { ) -> Result<DbActorProfile, ImportError> {
if actor_address.instance == instance.host() { if actor_address.hostname == instance.host() {
return Err(ImportError::LocalObject); return Err(ImportError::LocalObject);
}; };
let actor_id = perform_webfinger_query(instance, actor_address).await?; let actor_id = perform_webfinger_query(instance, actor_address).await?;

View file

@ -42,15 +42,15 @@ fn parse_profile_query(query: &str) ->
{ {
// See also: ACTOR_ADDRESS_RE in activitypub::actors::types // See also: ACTOR_ADDRESS_RE in activitypub::actors::types
let acct_query_re = let acct_query_re =
Regex::new(r"^(@|!)?(?P<user>[\w\.-]+)(@(?P<instance>[\w\.-]+))?$").unwrap(); Regex::new(r"^(@|!)?(?P<username>[\w\.-]+)(@(?P<hostname>[\w\.-]+))?$").unwrap();
let acct_query_caps = acct_query_re.captures(query) let acct_query_caps = acct_query_re.captures(query)
.ok_or(ValidationError("invalid profile query"))?; .ok_or(ValidationError("invalid profile query"))?;
let username = acct_query_caps.name("user") let username = acct_query_caps.name("username")
.ok_or(ValidationError("invalid profile query"))? .ok_or(ValidationError("invalid profile query"))?
.as_str().to_string(); .as_str().to_string();
let maybe_instance = acct_query_caps.name("instance") let maybe_hostname = acct_query_caps.name("hostname")
.map(|val| val.as_str().to_string()); .map(|val| val.as_str().to_string());
Ok((username, maybe_instance)) Ok((username, maybe_hostname))
} }
fn parse_tag_query(query: &str) -> Result<String, ValidationError> { fn parse_tag_query(query: &str) -> Result<String, ValidationError> {
@ -82,8 +82,8 @@ fn parse_search_query(search_query: &str) -> SearchQuery {
if let Ok(tag) = parse_tag_query(search_query) { if let Ok(tag) = parse_tag_query(search_query) {
return SearchQuery::TagQuery(tag); return SearchQuery::TagQuery(tag);
}; };
if let Ok((username, maybe_instance)) = parse_profile_query(search_query) { if let Ok((username, maybe_hostname)) = parse_profile_query(search_query) {
return SearchQuery::ProfileQuery(username, maybe_instance); return SearchQuery::ProfileQuery(username, maybe_hostname);
}; };
SearchQuery::Unknown SearchQuery::Unknown
} }
@ -92,25 +92,25 @@ async fn search_profiles_or_import(
config: &Config, config: &Config,
db_client: &impl GenericClient, db_client: &impl GenericClient,
username: String, username: String,
mut instance: Option<String>, mut maybe_hostname: Option<String>,
limit: u16, limit: u16,
) -> Result<Vec<DbActorProfile>, HttpError> { ) -> Result<Vec<DbActorProfile>, HttpError> {
if let Some(ref actor_host) = instance { if let Some(ref hostname) = maybe_hostname {
if actor_host == &config.instance().host() { if hostname == &config.instance().host() {
// This is a local profile // This is a local profile
instance = None; maybe_hostname = None;
}; };
}; };
let mut profiles = search_profiles( let mut profiles = search_profiles(
db_client, db_client,
&username, &username,
instance.as_ref(), maybe_hostname.as_ref(),
limit, limit,
).await?; ).await?;
if profiles.is_empty() && instance.is_some() { if profiles.is_empty() && maybe_hostname.is_some() {
let actor_address = ActorAddress { let actor_address = ActorAddress {
username: username, username: username,
instance: instance.unwrap(), hostname: maybe_hostname.unwrap(),
}; };
match import_profile_by_actor_address( match import_profile_by_actor_address(
db_client, db_client,
@ -160,12 +160,12 @@ pub async fn search(
let mut posts = vec![]; let mut posts = vec![];
let mut tags = vec![]; let mut tags = vec![];
match parse_search_query(search_query) { match parse_search_query(search_query) {
SearchQuery::ProfileQuery(username, maybe_instance) => { SearchQuery::ProfileQuery(username, maybe_hostname) => {
profiles = search_profiles_or_import( profiles = search_profiles_or_import(
config, config,
db_client, db_client,
username, username,
maybe_instance, maybe_hostname,
limit, limit,
).await?; ).await?;
}, },
@ -224,14 +224,14 @@ pub async fn search_profiles_only(
search_query: &str, search_query: &str,
limit: u16, limit: u16,
) -> Result<Vec<Account>, HttpError> { ) -> Result<Vec<Account>, HttpError> {
let (username, maybe_instance) = match parse_profile_query(search_query) { let (username, maybe_hostname) = match parse_profile_query(search_query) {
Ok(result) => result, Ok(result) => result,
Err(_) => return Ok(vec![]), Err(_) => return Ok(vec![]),
}; };
let profiles = search_profiles( let profiles = search_profiles(
db_client, db_client,
&username, &username,
maybe_instance.as_ref(), maybe_hostname.as_ref(),
limit, limit,
).await?; ).await?;
let accounts: Vec<Account> = profiles.into_iter() let accounts: Vec<Account> = profiles.into_iter()
@ -247,17 +247,17 @@ mod tests {
#[test] #[test]
fn test_parse_profile_query() { fn test_parse_profile_query() {
let query = "@user"; let query = "@user";
let (username, maybe_instance) = parse_profile_query(query).unwrap(); let (username, maybe_hostname) = parse_profile_query(query).unwrap();
assert_eq!(username, "user"); assert_eq!(username, "user");
assert_eq!(maybe_instance, None); assert_eq!(maybe_hostname, None);
} }
#[test] #[test]
fn test_parse_profile_query_group() { fn test_parse_profile_query_group() {
let query = "!group@example.com"; let query = "!group@example.com";
let (username, maybe_instance) = parse_profile_query(query).unwrap(); let (username, maybe_hostname) = parse_profile_query(query).unwrap();
assert_eq!(username, "group"); assert_eq!(username, "group");
assert_eq!(maybe_instance.as_deref(), Some("example.com")); assert_eq!(maybe_hostname.as_deref(), Some("example.com"));
} }
#[test] #[test]

View file

@ -9,9 +9,9 @@ use crate::models::profiles::queries::get_profiles_by_accts;
use crate::models::profiles::types::DbActorProfile; use crate::models::profiles::types::DbActorProfile;
// See also: ACTOR_ADDRESS_RE in activitypub::actors::types // See also: ACTOR_ADDRESS_RE in activitypub::actors::types
const MENTION_RE: &str = r"@?(?P<user>[\w\.-]+)@(?P<instance>.+)"; const MENTION_RE: &str = r"@?(?P<username>[\w\.-]+)@(?P<hostname>.+)";
const MENTION_SEARCH_RE: &str = r"(?m)(?P<before>^|\s|>|[\(])@(?P<mention>[^\s<]+)"; const MENTION_SEARCH_RE: &str = r"(?m)(?P<before>^|\s|>|[\(])@(?P<mention>[^\s<]+)";
const MENTION_SEARCH_SECONDARY_RE: &str = r"^(?P<user>[\w\.-]+)(@(?P<instance>[\w\.-]+\w))?(?P<after>[\.,:?\)]?)$"; const MENTION_SEARCH_SECONDARY_RE: &str = r"^(?P<username>[\w\.-]+)(@(?P<hostname>[\w\.-]+\w))?(?P<after>[\.,:?\)]?)$";
/// Finds everything that looks like a mention /// Finds everything that looks like a mention
fn find_mentions( fn find_mentions(
@ -23,12 +23,12 @@ fn find_mentions(
let mut mentions = vec![]; let mut mentions = vec![];
for caps in mention_re.captures_iter(text) { for caps in mention_re.captures_iter(text) {
if let Some(secondary_caps) = mention_secondary_re.captures(&caps["mention"]) { if let Some(secondary_caps) = mention_secondary_re.captures(&caps["mention"]) {
let username = secondary_caps["user"].to_string(); let username = secondary_caps["username"].to_string();
let instance = secondary_caps.name("instance") let hostname = secondary_caps.name("hostname")
.map(|match_| match_.as_str()) .map(|match_| match_.as_str())
.unwrap_or(instance_host) .unwrap_or(instance_host)
.to_string(); .to_string();
let actor_address = ActorAddress { username, instance }; let actor_address = ActorAddress { username, hostname };
let acct = actor_address.acct(instance_host); let acct = actor_address.acct(instance_host);
if !mentions.contains(&acct) { if !mentions.contains(&acct) {
mentions.push(acct); mentions.push(acct);
@ -62,12 +62,12 @@ pub fn replace_mentions(
let mention_secondary_re = Regex::new(MENTION_SEARCH_SECONDARY_RE).unwrap(); let mention_secondary_re = Regex::new(MENTION_SEARCH_SECONDARY_RE).unwrap();
let result = mention_re.replace_all(text, |caps: &Captures| { let result = mention_re.replace_all(text, |caps: &Captures| {
if let Some(secondary_caps) = mention_secondary_re.captures(&caps["mention"]) { if let Some(secondary_caps) = mention_secondary_re.captures(&caps["mention"]) {
let username = secondary_caps["user"].to_string(); let username = secondary_caps["username"].to_string();
let instance = secondary_caps.name("instance") let hostname = secondary_caps.name("hostname")
.map(|match_| match_.as_str()) .map(|match_| match_.as_str())
.unwrap_or(instance_host) .unwrap_or(instance_host)
.to_string(); .to_string();
let actor_address = ActorAddress { username, instance }; let actor_address = ActorAddress { username, hostname };
let acct = actor_address.acct(instance_host); let acct = actor_address.acct(instance_host);
if let Some(profile) = mention_map.get(&acct) { if let Some(profile) = mention_map.get(&acct) {
// Replace with a link to profile. // Replace with a link to profile.
@ -97,8 +97,8 @@ pub fn mention_to_address(
let mention_caps = mention_re.captures(mention) let mention_caps = mention_re.captures(mention)
.ok_or(ValidationError("invalid mention tag"))?; .ok_or(ValidationError("invalid mention tag"))?;
let actor_address = ActorAddress { let actor_address = ActorAddress {
username: mention_caps["user"].to_string(), username: mention_caps["username"].to_string(),
instance: mention_caps["instance"].to_string(), hostname: mention_caps["hostname"].to_string(),
}; };
Ok(actor_address) Ok(actor_address)
} }

View file

@ -372,13 +372,13 @@ pub async fn delete_profile(
pub async fn search_profiles( pub async fn search_profiles(
db_client: &impl GenericClient, db_client: &impl GenericClient,
username: &str, username: &str,
instance: Option<&String>, maybe_hostname: Option<&String>,
limit: u16, limit: u16,
) -> Result<Vec<DbActorProfile>, DatabaseError> { ) -> Result<Vec<DbActorProfile>, DatabaseError> {
let db_search_query = match instance { let db_search_query = match maybe_hostname {
Some(instance) => { Some(hostname) => {
// Search for exact actor address // Search for exact actor address
format!("{}@{}", username, instance) format!("{}@{}", username, hostname)
}, },
None => { None => {
// Fuzzy search for username // Fuzzy search for username

View file

@ -276,7 +276,7 @@ impl DbActorProfile {
assert_eq!(self.hostname.is_none(), self.is_local()); assert_eq!(self.hostname.is_none(), self.is_local());
ActorAddress { ActorAddress {
username: self.username.clone(), username: self.username.clone(),
instance: self.hostname.as_deref() hostname: self.hostname.as_deref()
.unwrap_or(instance_host) .unwrap_or(instance_host)
.to_string(), .to_string(),
} }

View file

@ -26,7 +26,7 @@ fn parse_acct_uri(uri: &str) -> Result<ActorAddress, ValidationError> {
.ok_or(ValidationError("invalid query target"))?; .ok_or(ValidationError("invalid query target"))?;
let actor_address = ActorAddress { let actor_address = ActorAddress {
username: uri_caps["username"].to_string(), username: uri_caps["username"].to_string(),
instance: uri_caps["instance"].to_string(), hostname: uri_caps["hostname"].to_string(),
}; };
Ok(actor_address) Ok(actor_address)
} }
@ -88,6 +88,6 @@ mod tests {
let uri = "acct:user_1@example.com"; let uri = "acct:user_1@example.com";
let actor_address = parse_acct_uri(uri).unwrap(); let actor_address = parse_acct_uri(uri).unwrap();
assert_eq!(actor_address.username, "user_1"); assert_eq!(actor_address.username, "user_1");
assert_eq!(actor_address.instance, "example.com"); assert_eq!(actor_address.hostname, "example.com");
} }
} }