Create instance actor
This commit is contained in:
parent
52b51501d5
commit
d935b843a8
6 changed files with 91 additions and 19 deletions
|
@ -1,6 +1,7 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::config::Instance;
|
||||
use crate::errors::ConversionError;
|
||||
use crate::models::profiles::types::{DbActorProfile, ExtraField};
|
||||
use crate::models::users::types::User;
|
||||
|
@ -14,7 +15,7 @@ use super::views::{
|
|||
get_followers_url,
|
||||
get_following_url,
|
||||
};
|
||||
use super::vocabulary::{PERSON, IMAGE, PROPERTY_VALUE};
|
||||
use super::vocabulary::{IMAGE, PERSON, PROPERTY_VALUE, SERVICE};
|
||||
|
||||
const W3ID_CONTEXT: &str = "https://w3id.org/security/v1";
|
||||
|
||||
|
@ -63,8 +64,12 @@ pub struct Actor {
|
|||
pub preferred_username: String,
|
||||
pub inbox: String,
|
||||
pub outbox: String,
|
||||
pub followers: String,
|
||||
pub following: String,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub followers: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub following: Option<String>,
|
||||
|
||||
pub public_key: PublicKey,
|
||||
|
||||
|
@ -80,6 +85,7 @@ pub struct Actor {
|
|||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub summary: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub attachment: Option<Vec<ActorProperty>>,
|
||||
}
|
||||
|
||||
|
@ -178,8 +184,8 @@ pub fn get_local_actor(
|
|||
preferred_username: username.to_string(),
|
||||
inbox,
|
||||
outbox,
|
||||
followers,
|
||||
following,
|
||||
followers: Some(followers),
|
||||
following: Some(following),
|
||||
public_key,
|
||||
capabilities: Some(capabilities),
|
||||
icon: avatar,
|
||||
|
@ -189,3 +195,38 @@ pub fn get_local_actor(
|
|||
};
|
||||
Ok(actor)
|
||||
}
|
||||
|
||||
pub fn get_instance_actor(
|
||||
instance: &Instance,
|
||||
) -> Result<Actor, ActorKeyError> {
|
||||
let actor_id = instance.actor_id();
|
||||
let actor_inbox = format!("{}/inbox", actor_id);
|
||||
let actor_outbox = format!("{}/outbox", actor_id);
|
||||
let public_key_pem = get_public_key_pem(&instance.actor_key)?;
|
||||
let public_key = PublicKey {
|
||||
id: instance.actor_key_id(),
|
||||
owner: actor_id.clone(),
|
||||
public_key_pem: public_key_pem,
|
||||
};
|
||||
let actor = Actor {
|
||||
context: Some(json!([
|
||||
AP_CONTEXT.to_string(),
|
||||
W3ID_CONTEXT.to_string(),
|
||||
])),
|
||||
id: actor_id,
|
||||
object_type: SERVICE.to_string(),
|
||||
name: instance.host(),
|
||||
preferred_username: instance.host(),
|
||||
inbox: actor_inbox,
|
||||
outbox: actor_outbox,
|
||||
followers: None,
|
||||
following: None,
|
||||
public_key,
|
||||
capabilities: None,
|
||||
icon: None,
|
||||
image: None,
|
||||
summary: None,
|
||||
attachment: None,
|
||||
};
|
||||
Ok(actor)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::http_signatures::verify::verify_http_signature;
|
|||
use crate::models::posts::queries::get_thread;
|
||||
use crate::models::users::queries::get_user_by_name;
|
||||
use super::activity::{create_note, OrderedCollection};
|
||||
use super::actor::get_local_actor;
|
||||
use super::actor::{get_local_actor, get_instance_actor};
|
||||
use super::constants::ACTIVITY_CONTENT_TYPE;
|
||||
use super::receiver::receive_activity;
|
||||
|
||||
|
@ -37,6 +37,10 @@ pub fn get_following_url(instance_url: &str, username: &str) -> String {
|
|||
format!("{}/users/{}/following", instance_url, username)
|
||||
}
|
||||
|
||||
pub fn get_instance_actor_url(instance_url: &str) -> String {
|
||||
format!("{}/actor", instance_url)
|
||||
}
|
||||
|
||||
pub fn get_object_url(instance_url: &str, object_uuid: &Uuid) -> String {
|
||||
format!("{}/objects/{}", instance_url, object_uuid)
|
||||
}
|
||||
|
@ -55,7 +59,7 @@ fn is_activitypub_request(request: &HttpRequest) -> bool {
|
|||
}
|
||||
|
||||
#[get("")]
|
||||
async fn get_actor(
|
||||
async fn actor_view(
|
||||
config: web::Data<Config>,
|
||||
db_pool: web::Data<Pool>,
|
||||
request: HttpRequest,
|
||||
|
@ -135,16 +139,28 @@ async fn following_collection(
|
|||
Ok(response)
|
||||
}
|
||||
|
||||
pub fn activitypub_scope() -> Scope {
|
||||
pub fn actor_scope() -> Scope {
|
||||
web::scope("/users/{username}")
|
||||
.service(get_actor)
|
||||
.service(actor_view)
|
||||
.service(inbox)
|
||||
.service(followers_collection)
|
||||
.service(following_collection)
|
||||
}
|
||||
|
||||
#[get("/actor")]
|
||||
pub async fn instance_actor_view(
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, HttpError> {
|
||||
let actor = get_instance_actor(&config.instance())
|
||||
.map_err(|_| HttpError::InternalError)?;
|
||||
let response = HttpResponse::Ok()
|
||||
.content_type(ACTIVITY_CONTENT_TYPE)
|
||||
.json(actor);
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
#[get("/objects/{object_id}")]
|
||||
pub async fn get_object(
|
||||
pub async fn object_view(
|
||||
config: web::Data<Config>,
|
||||
db_pool: web::Data<Pool>,
|
||||
request: HttpRequest,
|
||||
|
|
|
@ -12,6 +12,7 @@ pub const UPDATE: &str = "Update";
|
|||
|
||||
// Actor types
|
||||
pub const PERSON: &str = "Person";
|
||||
pub const SERVICE: &str = "Service";
|
||||
|
||||
// Object types
|
||||
pub const DOCUMENT: &str = "Document";
|
||||
|
|
|
@ -5,6 +5,7 @@ use rsa::RsaPrivateKey;
|
|||
use serde::{de, Deserialize, Deserializer};
|
||||
use url::Url;
|
||||
|
||||
use crate::activitypub::views::get_instance_actor_url;
|
||||
use crate::errors::ConversionError;
|
||||
use crate::utils::crypto::deserialize_private_key;
|
||||
|
||||
|
@ -152,6 +153,14 @@ impl Instance {
|
|||
pub fn host(&self) -> String {
|
||||
self._url.host_str().unwrap().to_string()
|
||||
}
|
||||
|
||||
pub fn actor_id(&self) -> String {
|
||||
get_instance_actor_url(&self.url())
|
||||
}
|
||||
|
||||
pub fn actor_key_id(&self) -> String {
|
||||
format!("{}#main-key", self.actor_id())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_config() -> Config {
|
||||
|
|
|
@ -5,7 +5,7 @@ use actix_web::{
|
|||
middleware::Logger as ActixLogger,
|
||||
};
|
||||
|
||||
use mitra::activitypub::views::{activitypub_scope, get_object};
|
||||
use mitra::activitypub::views as activitypub;
|
||||
use mitra::config::{Environment, parse_config};
|
||||
use mitra::database::create_pool;
|
||||
use mitra::database::migrate::apply_migrations;
|
||||
|
@ -87,8 +87,9 @@ async fn main() -> std::io::Result<()> {
|
|||
.service(search_api_scope())
|
||||
.service(timeline_api_scope())
|
||||
.service(webfinger::get_descriptor)
|
||||
.service(activitypub_scope())
|
||||
.service(get_object)
|
||||
.service(activitypub::actor_scope())
|
||||
.service(activitypub::instance_actor_view)
|
||||
.service(activitypub::object_view)
|
||||
.service(nodeinfo::get_nodeinfo)
|
||||
.service(nodeinfo::get_nodeinfo_2_0);
|
||||
if let Some(contract_dir) = &config.ethereum_contract_dir {
|
||||
|
|
|
@ -2,7 +2,7 @@ use actix_web::{get, web, HttpResponse};
|
|||
use regex::Regex;
|
||||
use tokio_postgres::GenericClient;
|
||||
|
||||
use crate::activitypub::views::get_actor_url;
|
||||
use crate::activitypub::views::{get_actor_url, get_instance_actor_url};
|
||||
use crate::activitypub::constants::ACTIVITY_CONTENT_TYPE;
|
||||
use crate::config::{Config, Instance};
|
||||
use crate::database::{Pool, get_database_client};
|
||||
|
@ -22,7 +22,7 @@ async fn get_user_info(
|
|||
) -> Result<JsonResourceDescriptor, HttpError> {
|
||||
// Parse 'acct' URI
|
||||
// https://datatracker.ietf.org/doc/html/rfc7565#section-7
|
||||
let uri_regexp = Regex::new(r"acct:(?P<user>\w+)@(?P<instance>.+)").unwrap();
|
||||
let uri_regexp = Regex::new(r"acct:(?P<user>[\w\.]+)@(?P<instance>.+)").unwrap();
|
||||
let uri_caps = uri_regexp.captures(&query_params.resource)
|
||||
.ok_or(ValidationError("invalid query target"))?;
|
||||
let username = uri_caps.name("user")
|
||||
|
@ -36,10 +36,14 @@ async fn get_user_info(
|
|||
// Wrong instance
|
||||
return Err(HttpError::NotFoundError("user"));
|
||||
}
|
||||
if !is_registered_user(db_client, username).await? {
|
||||
return Err(HttpError::NotFoundError("user"));
|
||||
}
|
||||
let actor_url = get_actor_url(&instance.url(), username);
|
||||
let actor_url = if username == instance.host() {
|
||||
get_instance_actor_url(&instance.url())
|
||||
} else {
|
||||
if !is_registered_user(db_client, username).await? {
|
||||
return Err(HttpError::NotFoundError("user"));
|
||||
};
|
||||
get_actor_url(&instance.url(), username)
|
||||
};
|
||||
let link = Link {
|
||||
rel: "self".to_string(),
|
||||
link_type: Some(ACTIVITY_CONTENT_TYPE.to_string()),
|
||||
|
|
Loading…
Reference in a new issue