2023-02-19 22:14:10 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
2022-11-22 18:59:42 +00:00
|
|
|
use serde::{
|
|
|
|
Deserialize,
|
|
|
|
Deserializer,
|
|
|
|
Serialize,
|
|
|
|
de::{Error as DeserializerError},
|
|
|
|
};
|
2021-04-09 00:22:17 +00:00
|
|
|
use serde_json::{json, Value};
|
|
|
|
|
2023-02-18 23:52:48 +00:00
|
|
|
use mitra_config::Instance;
|
2023-02-18 22:25:49 +00:00
|
|
|
use mitra_utils::{
|
|
|
|
crypto_rsa::{deserialize_private_key, get_public_key_pem},
|
|
|
|
urls::get_hostname,
|
|
|
|
};
|
|
|
|
|
2022-07-23 21:37:21 +00:00
|
|
|
use crate::activitypub::{
|
2023-01-28 22:35:46 +00:00
|
|
|
constants::{
|
|
|
|
AP_CONTEXT,
|
2023-02-19 22:14:10 +00:00
|
|
|
MASTODON_CONTEXT,
|
|
|
|
MITRA_CONTEXT,
|
|
|
|
SCHEMA_ORG_CONTEXT,
|
2023-01-28 22:35:46 +00:00
|
|
|
W3ID_SECURITY_CONTEXT,
|
|
|
|
},
|
2023-02-07 18:28:19 +00:00
|
|
|
identifiers::{
|
|
|
|
local_actor_id,
|
|
|
|
local_actor_key_id,
|
|
|
|
local_instance_actor_id,
|
|
|
|
LocalActorCollection,
|
|
|
|
},
|
2023-01-17 18:01:57 +00:00
|
|
|
receiver::parse_property_value,
|
2023-03-03 22:08:38 +00:00
|
|
|
types::deserialize_value_array,
|
2022-07-23 20:21:23 +00:00
|
|
|
vocabulary::{IDENTITY_PROOF, IMAGE, LINK, PERSON, PROPERTY_VALUE, SERVICE},
|
2022-07-23 21:37:21 +00:00
|
|
|
};
|
2022-07-23 20:21:23 +00:00
|
|
|
use crate::errors::ValidationError;
|
2023-02-12 18:54:29 +00:00
|
|
|
use crate::media::get_file_url;
|
2023-02-12 23:07:19 +00:00
|
|
|
use crate::models::{
|
|
|
|
profiles::types::{
|
2023-03-16 20:09:13 +00:00
|
|
|
DbActor,
|
|
|
|
DbActorPublicKey,
|
2023-02-12 23:07:19 +00:00
|
|
|
ExtraField,
|
|
|
|
IdentityProof,
|
|
|
|
PaymentOption,
|
|
|
|
},
|
|
|
|
users::types::User,
|
|
|
|
};
|
2023-01-10 21:26:42 +00:00
|
|
|
use crate::webfinger::types::ActorAddress;
|
2022-07-23 22:02:47 +00:00
|
|
|
use super::attachments::{
|
|
|
|
attach_extra_field,
|
|
|
|
attach_identity_proof,
|
2022-07-23 20:21:23 +00:00
|
|
|
attach_payment_option,
|
2022-07-23 22:02:47 +00:00
|
|
|
parse_extra_field,
|
|
|
|
parse_identity_proof,
|
2022-07-23 20:21:23 +00:00
|
|
|
parse_payment_option,
|
2022-07-23 22:02:47 +00:00
|
|
|
};
|
2021-04-09 00:22:17 +00:00
|
|
|
|
2023-03-16 20:09:13 +00:00
|
|
|
#[derive(Deserialize, Serialize)]
|
2021-12-31 15:29:44 +00:00
|
|
|
#[cfg_attr(test, derive(Default))]
|
2021-04-09 00:22:17 +00:00
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct PublicKey {
|
|
|
|
id: String,
|
|
|
|
owner: String,
|
|
|
|
pub public_key_pem: String,
|
|
|
|
}
|
|
|
|
|
2023-03-16 20:09:13 +00:00
|
|
|
#[derive(Deserialize, Serialize)]
|
2021-04-09 00:22:17 +00:00
|
|
|
#[serde(rename_all = "camelCase")]
|
2023-01-06 22:34:50 +00:00
|
|
|
pub struct ActorImage {
|
2021-04-09 00:22:17 +00:00
|
|
|
#[serde(rename = "type")]
|
|
|
|
object_type: String,
|
|
|
|
pub url: String,
|
2023-01-04 20:04:10 +00:00
|
|
|
pub media_type: Option<String>,
|
2021-04-09 00:22:17 +00:00
|
|
|
}
|
|
|
|
|
2023-03-16 20:09:13 +00:00
|
|
|
#[derive(Deserialize, Serialize)]
|
2022-04-16 18:48:00 +00:00
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct ActorAttachment {
|
2022-07-23 22:02:47 +00:00
|
|
|
pub name: String,
|
2022-04-16 18:48:00 +00:00
|
|
|
|
2021-09-17 12:36:24 +00:00
|
|
|
#[serde(rename = "type")]
|
2022-07-23 22:02:47 +00:00
|
|
|
pub object_type: String,
|
2022-04-16 18:48:00 +00:00
|
|
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-07-23 22:02:47 +00:00
|
|
|
pub value: Option<String>,
|
2022-04-16 18:48:00 +00:00
|
|
|
|
2022-07-23 20:21:23 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
pub href: Option<String>,
|
|
|
|
|
2022-04-16 18:48:00 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-07-23 22:02:47 +00:00
|
|
|
pub signature_algorithm: Option<String>,
|
2022-04-16 18:48:00 +00:00
|
|
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-07-23 22:02:47 +00:00
|
|
|
pub signature_value: Option<String>,
|
2021-09-17 12:36:24 +00:00
|
|
|
}
|
|
|
|
|
2022-11-22 18:59:42 +00:00
|
|
|
// Some implementations use empty object instead of null
|
2023-01-17 18:01:57 +00:00
|
|
|
fn deserialize_image_opt<'de, D>(
|
2022-11-22 18:59:42 +00:00
|
|
|
deserializer: D,
|
2023-01-06 22:34:50 +00:00
|
|
|
) -> Result<Option<ActorImage>, D::Error>
|
2022-11-22 18:59:42 +00:00
|
|
|
where D: Deserializer<'de>
|
|
|
|
{
|
|
|
|
let maybe_value: Option<Value> = Option::deserialize(deserializer)?;
|
|
|
|
let maybe_image = if let Some(value) = maybe_value {
|
|
|
|
let is_empty_object = value.as_object()
|
|
|
|
.map(|map| map.is_empty())
|
|
|
|
.unwrap_or(false);
|
|
|
|
if is_empty_object {
|
|
|
|
None
|
|
|
|
} else {
|
2023-01-06 22:34:50 +00:00
|
|
|
let image = ActorImage::deserialize(value)
|
2022-11-22 18:59:42 +00:00
|
|
|
.map_err(DeserializerError::custom)?;
|
|
|
|
Some(image)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
Ok(maybe_image)
|
|
|
|
}
|
|
|
|
|
2023-01-17 18:01:57 +00:00
|
|
|
// Some implementations use single object instead of array
|
2023-02-27 23:47:44 +00:00
|
|
|
fn deserialize_attachments<'de, D>(
|
2023-01-17 18:01:57 +00:00
|
|
|
deserializer: D,
|
2023-02-27 23:47:44 +00:00
|
|
|
) -> Result<Vec<ActorAttachment>, D::Error>
|
2023-01-17 18:01:57 +00:00
|
|
|
where D: Deserializer<'de>
|
|
|
|
{
|
|
|
|
let maybe_value: Option<Value> = Option::deserialize(deserializer)?;
|
2023-02-27 23:47:44 +00:00
|
|
|
let attachments = if let Some(value) = maybe_value {
|
|
|
|
parse_property_value(&value).map_err(DeserializerError::custom)?
|
2023-01-17 18:01:57 +00:00
|
|
|
} else {
|
2023-02-27 23:47:44 +00:00
|
|
|
vec![]
|
2023-01-17 18:01:57 +00:00
|
|
|
};
|
2023-02-27 23:47:44 +00:00
|
|
|
Ok(attachments)
|
2023-01-17 18:01:57 +00:00
|
|
|
}
|
|
|
|
|
2023-03-16 20:09:13 +00:00
|
|
|
#[derive(Deserialize, Serialize)]
|
2021-12-31 15:29:44 +00:00
|
|
|
#[cfg_attr(test, derive(Default))]
|
2021-04-09 00:22:17 +00:00
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct Actor {
|
|
|
|
#[serde(rename = "@context")]
|
2021-12-31 15:29:44 +00:00
|
|
|
pub context: Option<Value>,
|
2021-04-09 00:22:17 +00:00
|
|
|
|
|
|
|
pub id: String,
|
|
|
|
|
|
|
|
#[serde(rename = "type")]
|
2021-12-31 15:29:44 +00:00
|
|
|
pub object_type: String,
|
2021-04-09 00:22:17 +00:00
|
|
|
|
2021-12-20 00:12:18 +00:00
|
|
|
pub name: Option<String>,
|
|
|
|
|
2021-04-09 00:22:17 +00:00
|
|
|
pub preferred_username: String,
|
|
|
|
pub inbox: String,
|
|
|
|
pub outbox: String,
|
2021-11-18 00:51:56 +00:00
|
|
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
pub followers: Option<String>,
|
|
|
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
pub following: Option<String>,
|
2021-04-09 00:22:17 +00:00
|
|
|
|
2022-06-14 23:41:01 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
pub subscribers: Option<String>,
|
|
|
|
|
2021-04-09 00:22:17 +00:00
|
|
|
pub public_key: PublicKey,
|
|
|
|
|
2022-11-22 18:59:42 +00:00
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_image_opt",
|
|
|
|
skip_serializing_if = "Option::is_none",
|
|
|
|
)]
|
2023-01-06 22:34:50 +00:00
|
|
|
pub icon: Option<ActorImage>,
|
2021-04-09 00:22:17 +00:00
|
|
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2023-01-06 22:34:50 +00:00
|
|
|
pub image: Option<ActorImage>,
|
2021-04-09 00:22:17 +00:00
|
|
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
pub summary: Option<String>,
|
2021-09-17 12:36:24 +00:00
|
|
|
|
2022-10-21 21:32:01 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2022-11-17 22:49:31 +00:00
|
|
|
pub also_known_as: Option<Value>,
|
2022-10-21 21:32:01 +00:00
|
|
|
|
2023-01-17 18:01:57 +00:00
|
|
|
#[serde(
|
|
|
|
default,
|
2023-02-27 23:47:44 +00:00
|
|
|
deserialize_with = "deserialize_attachments",
|
|
|
|
skip_serializing_if = "Vec::is_empty",
|
2023-01-17 18:01:57 +00:00
|
|
|
)]
|
2023-02-27 23:47:44 +00:00
|
|
|
pub attachment: Vec<ActorAttachment>,
|
2021-12-11 23:25:00 +00:00
|
|
|
|
2022-12-14 09:24:12 +00:00
|
|
|
#[serde(default)]
|
|
|
|
pub manually_approves_followers: bool,
|
|
|
|
|
2023-03-03 22:08:38 +00:00
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_value_array",
|
|
|
|
skip_serializing_if = "Vec::is_empty",
|
|
|
|
)]
|
|
|
|
pub tag: Vec<Value>,
|
2023-01-07 20:33:23 +00:00
|
|
|
|
2021-12-11 23:25:00 +00:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
pub url: Option<String>,
|
2021-09-17 12:36:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Actor {
|
2022-07-10 19:41:27 +00:00
|
|
|
pub fn address(
|
|
|
|
&self,
|
2022-07-27 13:21:12 +00:00
|
|
|
) -> Result<ActorAddress, ValidationError> {
|
2022-10-17 21:59:22 +00:00
|
|
|
let hostname = get_hostname(&self.id)
|
|
|
|
.map_err(|_| ValidationError("invalid actor ID"))?;
|
2022-07-10 19:41:27 +00:00
|
|
|
let actor_address = ActorAddress {
|
|
|
|
username: self.preferred_username.clone(),
|
2022-10-09 14:26:58 +00:00
|
|
|
hostname: hostname,
|
2022-07-10 19:41:27 +00:00
|
|
|
};
|
|
|
|
Ok(actor_address)
|
|
|
|
}
|
2022-04-16 18:48:00 +00:00
|
|
|
|
2023-03-16 20:09:13 +00:00
|
|
|
pub fn into_db_actor(self) -> DbActor {
|
|
|
|
DbActor {
|
|
|
|
object_type: self.object_type,
|
|
|
|
id: self.id,
|
|
|
|
inbox: self.inbox,
|
|
|
|
outbox: self.outbox,
|
|
|
|
followers: self.followers,
|
|
|
|
subscribers: self.subscribers,
|
|
|
|
url: self.url,
|
|
|
|
public_key: DbActorPublicKey {
|
|
|
|
id: self.public_key.id,
|
|
|
|
owner: self.public_key.owner,
|
|
|
|
public_key_pem: self.public_key.public_key_pem,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-23 20:21:23 +00:00
|
|
|
pub fn parse_attachments(&self) -> (
|
|
|
|
Vec<IdentityProof>,
|
|
|
|
Vec<PaymentOption>,
|
|
|
|
Vec<ExtraField>,
|
|
|
|
) {
|
2022-04-16 18:48:00 +00:00
|
|
|
let mut identity_proofs = vec![];
|
2022-07-23 20:21:23 +00:00
|
|
|
let mut payment_options = vec![];
|
2021-12-20 23:07:02 +00:00
|
|
|
let mut extra_fields = vec![];
|
2022-07-23 20:21:23 +00:00
|
|
|
let log_error = |attachment: &ActorAttachment, error| {
|
|
|
|
log::warn!(
|
|
|
|
"ignoring actor attachment of type {}: {}",
|
|
|
|
attachment.object_type,
|
|
|
|
error,
|
|
|
|
);
|
|
|
|
};
|
2023-02-27 23:47:44 +00:00
|
|
|
for attachment in self.attachment.iter() {
|
|
|
|
match attachment.object_type.as_str() {
|
|
|
|
IDENTITY_PROOF => {
|
|
|
|
match parse_identity_proof(&self.id, attachment) {
|
|
|
|
Ok(proof) => identity_proofs.push(proof),
|
|
|
|
Err(error) => log_error(attachment, error),
|
|
|
|
};
|
|
|
|
},
|
|
|
|
LINK => {
|
|
|
|
match parse_payment_option(attachment) {
|
|
|
|
Ok(option) => payment_options.push(option),
|
|
|
|
Err(error) => log_error(attachment, error),
|
|
|
|
};
|
|
|
|
},
|
|
|
|
PROPERTY_VALUE => {
|
|
|
|
match parse_extra_field(attachment) {
|
|
|
|
Ok(field) => extra_fields.push(field),
|
|
|
|
Err(error) => log_error(attachment, error),
|
|
|
|
};
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
log_error(
|
|
|
|
attachment,
|
|
|
|
ValidationError("unsupported attachment type"),
|
|
|
|
);
|
|
|
|
},
|
2021-12-20 23:07:02 +00:00
|
|
|
};
|
|
|
|
};
|
2022-07-23 20:21:23 +00:00
|
|
|
(identity_proofs, payment_options, extra_fields)
|
2021-09-17 12:36:24 +00:00
|
|
|
}
|
2021-04-09 00:22:17 +00:00
|
|
|
}
|
|
|
|
|
2021-11-12 23:41:03 +00:00
|
|
|
pub type ActorKeyError = rsa::pkcs8::Error;
|
|
|
|
|
2023-02-19 22:14:10 +00:00
|
|
|
fn build_actor_context() -> (
|
|
|
|
&'static str,
|
|
|
|
&'static str,
|
|
|
|
HashMap<&'static str, &'static str>,
|
|
|
|
) {
|
|
|
|
(
|
|
|
|
AP_CONTEXT,
|
|
|
|
W3ID_SECURITY_CONTEXT,
|
|
|
|
HashMap::from([
|
|
|
|
("manuallyApprovesFollowers", "as:manuallyApprovesFollowers"),
|
|
|
|
("schema", SCHEMA_ORG_CONTEXT),
|
|
|
|
("PropertyValue", "schema:PropertyValue"),
|
|
|
|
("value", "schema:value"),
|
|
|
|
("toot", MASTODON_CONTEXT),
|
|
|
|
("IdentityProof", "toot:IdentityProof"),
|
|
|
|
("mitra", MITRA_CONTEXT),
|
|
|
|
("subscribers", "mitra:subscribers"),
|
|
|
|
]),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-11-12 23:41:03 +00:00
|
|
|
pub fn get_local_actor(
|
2021-04-09 00:22:17 +00:00
|
|
|
user: &User,
|
2021-11-12 23:41:03 +00:00
|
|
|
instance_url: &str,
|
|
|
|
) -> Result<Actor, ActorKeyError> {
|
2021-04-09 00:22:17 +00:00
|
|
|
let username = &user.profile.username;
|
2022-07-15 17:31:02 +00:00
|
|
|
let actor_id = local_actor_id(instance_url, username);
|
|
|
|
let inbox = LocalActorCollection::Inbox.of(&actor_id);
|
|
|
|
let outbox = LocalActorCollection::Outbox.of(&actor_id);
|
|
|
|
let followers = LocalActorCollection::Followers.of(&actor_id);
|
|
|
|
let following = LocalActorCollection::Following.of(&actor_id);
|
|
|
|
let subscribers = LocalActorCollection::Subscribers.of(&actor_id);
|
2021-04-09 00:22:17 +00:00
|
|
|
|
2021-09-17 12:36:24 +00:00
|
|
|
let private_key = deserialize_private_key(&user.private_key)?;
|
|
|
|
let public_key_pem = get_public_key_pem(&private_key)?;
|
2021-04-09 00:22:17 +00:00
|
|
|
let public_key = PublicKey {
|
2023-02-07 18:28:19 +00:00
|
|
|
id: local_actor_key_id(&actor_id),
|
2021-12-11 23:25:00 +00:00
|
|
|
owner: actor_id.clone(),
|
2021-04-09 00:22:17 +00:00
|
|
|
public_key_pem: public_key_pem,
|
|
|
|
};
|
2023-01-06 21:49:15 +00:00
|
|
|
let avatar = match &user.profile.avatar {
|
|
|
|
Some(image) => {
|
2023-01-06 22:34:50 +00:00
|
|
|
let actor_image = ActorImage {
|
2021-04-09 00:22:17 +00:00
|
|
|
object_type: IMAGE.to_string(),
|
2023-01-06 21:49:15 +00:00
|
|
|
url: get_file_url(instance_url, &image.file_name),
|
2023-01-14 19:34:08 +00:00
|
|
|
media_type: image.media_type.clone(),
|
2021-04-09 00:22:17 +00:00
|
|
|
};
|
2023-01-06 22:34:50 +00:00
|
|
|
Some(actor_image)
|
2021-04-09 00:22:17 +00:00
|
|
|
},
|
|
|
|
None => None,
|
|
|
|
};
|
2023-01-06 21:49:15 +00:00
|
|
|
let banner = match &user.profile.banner {
|
|
|
|
Some(image) => {
|
2023-01-06 22:34:50 +00:00
|
|
|
let actor_image = ActorImage {
|
2021-04-09 00:22:17 +00:00
|
|
|
object_type: IMAGE.to_string(),
|
2023-01-06 21:49:15 +00:00
|
|
|
url: get_file_url(instance_url, &image.file_name),
|
2023-01-14 19:34:08 +00:00
|
|
|
media_type: image.media_type.clone(),
|
2021-04-09 00:22:17 +00:00
|
|
|
};
|
2023-01-06 22:34:50 +00:00
|
|
|
Some(actor_image)
|
2021-04-09 00:22:17 +00:00
|
|
|
},
|
|
|
|
None => None,
|
|
|
|
};
|
2022-04-16 18:48:00 +00:00
|
|
|
let mut attachments = vec![];
|
|
|
|
for proof in user.profile.identity_proofs.clone().into_inner() {
|
2022-07-23 22:02:47 +00:00
|
|
|
let attachment = attach_identity_proof(proof);
|
2022-04-16 18:48:00 +00:00
|
|
|
attachments.push(attachment);
|
|
|
|
};
|
2022-07-23 20:21:23 +00:00
|
|
|
for payment_option in user.profile.payment_options.clone().into_inner() {
|
|
|
|
let attachment = attach_payment_option(
|
|
|
|
instance_url,
|
2023-03-21 13:47:31 +00:00
|
|
|
&user.profile.username,
|
2022-07-23 20:21:23 +00:00
|
|
|
payment_option,
|
|
|
|
);
|
|
|
|
attachments.push(attachment);
|
|
|
|
};
|
2022-04-16 18:48:00 +00:00
|
|
|
for field in user.profile.extra_fields.clone().into_inner() {
|
2022-07-23 22:02:47 +00:00
|
|
|
let attachment = attach_extra_field(field);
|
2022-04-16 18:48:00 +00:00
|
|
|
attachments.push(attachment);
|
|
|
|
};
|
2021-04-09 00:22:17 +00:00
|
|
|
let actor = Actor {
|
2023-02-19 22:14:10 +00:00
|
|
|
context: Some(json!(build_actor_context())),
|
2021-12-11 23:25:00 +00:00
|
|
|
id: actor_id.clone(),
|
2021-04-09 00:22:17 +00:00
|
|
|
object_type: PERSON.to_string(),
|
2021-12-20 00:12:18 +00:00
|
|
|
name: user.profile.display_name.clone(),
|
2021-04-09 00:22:17 +00:00
|
|
|
preferred_username: username.to_string(),
|
|
|
|
inbox,
|
|
|
|
outbox,
|
2021-11-18 00:51:56 +00:00
|
|
|
followers: Some(followers),
|
|
|
|
following: Some(following),
|
2022-06-14 23:41:01 +00:00
|
|
|
subscribers: Some(subscribers),
|
2021-04-09 00:22:17 +00:00
|
|
|
public_key,
|
|
|
|
icon: avatar,
|
|
|
|
image: banner,
|
2022-05-24 17:55:26 +00:00
|
|
|
summary: user.profile.bio.clone(),
|
2022-10-21 21:32:01 +00:00
|
|
|
also_known_as: None,
|
2023-02-27 23:47:44 +00:00
|
|
|
attachment: attachments,
|
2022-12-14 09:24:12 +00:00
|
|
|
manually_approves_followers: false,
|
2023-03-03 22:08:38 +00:00
|
|
|
tag: vec![],
|
2021-12-11 23:25:00 +00:00
|
|
|
url: Some(actor_id),
|
2021-04-09 00:22:17 +00:00
|
|
|
};
|
|
|
|
Ok(actor)
|
|
|
|
}
|
2021-11-18 00:51:56 +00:00
|
|
|
|
|
|
|
pub fn get_instance_actor(
|
|
|
|
instance: &Instance,
|
|
|
|
) -> Result<Actor, ActorKeyError> {
|
2023-02-07 18:28:19 +00:00
|
|
|
let actor_id = local_instance_actor_id(&instance.url());
|
2022-07-15 19:36:21 +00:00
|
|
|
let actor_inbox = LocalActorCollection::Inbox.of(&actor_id);
|
|
|
|
let actor_outbox = LocalActorCollection::Outbox.of(&actor_id);
|
2021-11-18 00:51:56 +00:00
|
|
|
let public_key_pem = get_public_key_pem(&instance.actor_key)?;
|
|
|
|
let public_key = PublicKey {
|
2023-02-07 18:28:19 +00:00
|
|
|
id: local_actor_key_id(&actor_id),
|
2021-11-18 00:51:56 +00:00
|
|
|
owner: actor_id.clone(),
|
|
|
|
public_key_pem: public_key_pem,
|
|
|
|
};
|
|
|
|
let actor = Actor {
|
2023-02-19 22:14:10 +00:00
|
|
|
context: Some(json!(build_actor_context())),
|
2021-11-18 00:51:56 +00:00
|
|
|
id: actor_id,
|
|
|
|
object_type: SERVICE.to_string(),
|
2022-11-24 01:51:43 +00:00
|
|
|
name: Some(instance.hostname()),
|
|
|
|
preferred_username: instance.hostname(),
|
2021-11-18 00:51:56 +00:00
|
|
|
inbox: actor_inbox,
|
|
|
|
outbox: actor_outbox,
|
|
|
|
followers: None,
|
|
|
|
following: None,
|
2022-06-14 23:41:01 +00:00
|
|
|
subscribers: None,
|
2021-11-18 00:51:56 +00:00
|
|
|
public_key,
|
|
|
|
icon: None,
|
|
|
|
image: None,
|
|
|
|
summary: None,
|
2022-10-21 21:32:01 +00:00
|
|
|
also_known_as: None,
|
2023-02-27 23:47:44 +00:00
|
|
|
attachment: vec![],
|
2022-12-14 09:24:12 +00:00
|
|
|
manually_approves_followers: false,
|
2023-03-03 22:08:38 +00:00
|
|
|
tag: vec![],
|
2021-12-11 23:25:00 +00:00
|
|
|
url: None,
|
2021-11-18 00:51:56 +00:00
|
|
|
};
|
|
|
|
Ok(actor)
|
|
|
|
}
|
2022-04-26 22:35:39 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2023-02-18 22:25:49 +00:00
|
|
|
use mitra_utils::crypto_rsa::{
|
2022-11-13 18:43:57 +00:00
|
|
|
generate_weak_rsa_key,
|
2022-04-26 22:35:39 +00:00
|
|
|
serialize_private_key,
|
|
|
|
};
|
2023-02-18 22:25:49 +00:00
|
|
|
use crate::models::profiles::types::DbActorProfile;
|
2022-04-26 22:35:39 +00:00
|
|
|
use super::*;
|
|
|
|
|
2022-11-24 01:51:43 +00:00
|
|
|
const INSTANCE_HOSTNAME: &str = "example.com";
|
2022-04-26 22:35:39 +00:00
|
|
|
const INSTANCE_URL: &str = "https://example.com";
|
|
|
|
|
2022-07-10 19:41:27 +00:00
|
|
|
#[test]
|
|
|
|
fn test_get_actor_address() {
|
|
|
|
let actor = Actor {
|
|
|
|
id: "https://test.org/users/1".to_string(),
|
|
|
|
preferred_username: "test".to_string(),
|
|
|
|
..Default::default()
|
|
|
|
};
|
2022-10-03 21:21:20 +00:00
|
|
|
let actor_address = actor.address().unwrap();
|
2022-11-24 01:51:43 +00:00
|
|
|
assert_eq!(actor_address.acct(INSTANCE_HOSTNAME), "test@test.org");
|
2022-07-10 19:41:27 +00:00
|
|
|
}
|
|
|
|
|
2022-04-26 22:35:39 +00:00
|
|
|
#[test]
|
|
|
|
fn test_local_actor() {
|
2022-11-13 18:43:57 +00:00
|
|
|
let private_key = generate_weak_rsa_key().unwrap();
|
2022-04-30 19:26:09 +00:00
|
|
|
let private_key_pem = serialize_private_key(&private_key).unwrap();
|
2022-04-26 22:35:39 +00:00
|
|
|
let profile = DbActorProfile {
|
|
|
|
username: "testuser".to_string(),
|
2022-05-24 17:55:26 +00:00
|
|
|
bio: Some("testbio".to_string()),
|
2022-04-26 22:35:39 +00:00
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
let user = User {
|
|
|
|
private_key: private_key_pem,
|
|
|
|
profile,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
let actor = get_local_actor(&user, INSTANCE_URL).unwrap();
|
|
|
|
assert_eq!(actor.id, "https://example.com/users/testuser");
|
|
|
|
assert_eq!(actor.preferred_username, user.profile.username);
|
2022-07-15 19:57:55 +00:00
|
|
|
assert_eq!(actor.inbox, "https://example.com/users/testuser/inbox");
|
|
|
|
assert_eq!(actor.outbox, "https://example.com/users/testuser/outbox");
|
|
|
|
assert_eq!(
|
|
|
|
actor.followers.unwrap(),
|
|
|
|
"https://example.com/users/testuser/followers",
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
actor.following.unwrap(),
|
|
|
|
"https://example.com/users/testuser/following",
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
actor.subscribers.unwrap(),
|
|
|
|
"https://example.com/users/testuser/subscribers",
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
actor.public_key.id,
|
|
|
|
"https://example.com/users/testuser#main-key",
|
|
|
|
);
|
2023-02-27 23:47:44 +00:00
|
|
|
assert_eq!(actor.attachment.len(), 0);
|
2022-05-24 17:55:26 +00:00
|
|
|
assert_eq!(actor.summary, user.profile.bio);
|
2022-04-26 22:35:39 +00:00
|
|
|
}
|
2022-07-15 19:57:55 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_instance_actor() {
|
2023-01-12 21:38:36 +00:00
|
|
|
let instance_url = "https://example.com/";
|
|
|
|
let instance = Instance::for_test(instance_url);
|
2022-07-15 19:57:55 +00:00
|
|
|
let actor = get_instance_actor(&instance).unwrap();
|
|
|
|
assert_eq!(actor.id, "https://example.com/actor");
|
|
|
|
assert_eq!(actor.object_type, "Service");
|
|
|
|
assert_eq!(actor.preferred_username, "example.com");
|
|
|
|
assert_eq!(actor.inbox, "https://example.com/actor/inbox");
|
|
|
|
assert_eq!(actor.outbox, "https://example.com/actor/outbox");
|
|
|
|
assert_eq!(actor.public_key.id, "https://example.com/actor#main-key");
|
|
|
|
}
|
2022-04-26 22:35:39 +00:00
|
|
|
}
|